aiobungie
A Pythonic async/await wrapper for interacting with the Bungie API.
Base client.
Example
import aiobungie
client = aiobungie.Client('YOUR_API_KEY')
# Search for Destiny2 users.
async def main() -> None:
users = await client.search_users('Crit')
# Iterate over the users and take the first 5 results.
for user in users.take(5):
print(f'{user.name} ({user.code})')
# Iterate through the users memberships.
for membership in user.memberships:
print(membership.type, membership.id)
client.run(main()) # or asyncio.run(main())
Single RESTClient instance.
The difference between base client and the REST clients:
- No Hight-Level concepts.
- All returned data are pure JSON objects from the API.
- No object creation.
Example
import aiobungie
async def main() -> None:
# Using `async with` context manager to close the session properly.
async with aiobungie.RESTClient("TOKEN") as rest:
payload = await rest.fetch_player('Fate怒', 4275)
for membership in payload:
print(membership['membershipId'], membership['iconPath'])
import asyncio
asyncio.run(main())
REST client pool.
A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.
Example
import aiobungie
import asyncio
pool = aiobungie.RESTPool("token")
async def func1() -> None:
async with pool.acquire() as instance:
tokens = await instance.fetch_oauth2_tokens('code')
pool.metadata['tokens'] = tokens
# Other instance may access the tokens from pool since its shared.
async def func2() -> None:
async with pool.acquire() as instance:
tokens = pool.metadata['tokens']
tokens = await instance.refresh_access_token(tokens.refresh_token)
async def main() -> None:
await asyncio.gather(func1(), func2())
asyncio.run(main())
Should you use the base client or the REST client? This returns to you. For an example if you're building a website.
You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.
Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
1# MIT License 2# 3# Copyright (c) 2020 - Present nxtlo 4# 5# Permission is hereby granted, free of charge, to any person obtaining a copy 6# of this software and associated documentation files (the "Software"), to deal 7# in the Software without restriction, including without limitation the rights 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9# copies of the Software, and to permit persons to whom the Software is 10# furnished to do so, subject to the following conditions: 11# 12# The above copyright notice and this permission notice shall be included in all 13# copies or substantial portions of the Software. 14# 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21# SOFTWARE. 22 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API. 24 25Base client. 26 27Example 28------- 29```py 30import aiobungie 31 32client = aiobungie.Client('YOUR_API_KEY') 33 34# Search for Destiny2 users. 35async def main() -> None: 36 users = await client.search_users('Crit') 37 38 # Iterate over the users and take the first 5 results. 39 for user in users.take(5): 40 print(f'{user.name} ({user.code})') 41 42 # Iterate through the users memberships. 43 for membership in user.memberships: 44 print(membership.type, membership.id) 45 46client.run(main()) # or asyncio.run(main()) 47``` 48 49Single RESTClient instance. 50 51The difference between base client and the REST clients: 52 53* No Hight-Level concepts. 54* All returned data are pure JSON objects from the API. 55* No object creation. 56 57Example 58------- 59```py 60import aiobungie 61 62async def main() -> None: 63 # Using `async with` context manager to close the session properly. 64 async with aiobungie.RESTClient("TOKEN") as rest: 65 payload = await rest.fetch_player('Fate怒', 4275) 66 67 for membership in payload: 68 print(membership['membershipId'], membership['iconPath']) 69 70import asyncio 71asyncio.run(main()) 72``` 73 74REST client pool. 75 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection. 77 78Example 79------- 80```py 81import aiobungie 82import asyncio 83 84pool = aiobungie.RESTPool("token") 85 86async def func1() -> None: 87 async with pool.acquire() as instance: 88 tokens = await instance.fetch_oauth2_tokens('code') 89 pool.metadata['tokens'] = tokens 90 91# Other instance may access the tokens from pool since its shared. 92 93async def func2() -> None: 94 async with pool.acquire() as instance: 95 tokens = pool.metadata['tokens'] 96 tokens = await instance.refresh_access_token(tokens.refresh_token) 97 98async def main() -> None: 99 await asyncio.gather(func1(), func2()) 100 101asyncio.run(main()) 102``` 103 104Should you use the base client or the REST client? 105This returns to you. For an example if you're building a website. 106 107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. 108Which gives you the freedom to deserialize it and implement your own logic in the front-end. 109 110Or of you're building a Discord bot for an example or something simple. The base client is the way to go. 111""" 112 113 114from __future__ import annotations 115 116from aiobungie import builders 117from aiobungie import crates 118from aiobungie import interfaces 119from aiobungie import traits 120from aiobungie import typedefs 121from aiobungie import url 122from aiobungie.client import Client 123from aiobungie.error import * 124from aiobungie.internal import iterators 125from aiobungie.internal.assets import Image 126from aiobungie.internal.enums import * 127from aiobungie.internal.factory import Factory 128from aiobungie.internal.iterators import * 129from aiobungie.rest import * 130from aiobungie.undefined import Undefined 131from aiobungie.undefined import UndefinedOr 132from aiobungie.undefined import UndefinedType 133 134from ._info import __about__ 135from ._info import __author__ 136from ._info import __docs__ 137from ._info import __email__ 138from ._info import __license__ 139from ._info import __url__ 140from ._info import __version__ 141 142# Alias for crate for backwards compatibility. 143crate = crates 144 145# Activity enums 146from .crates.activity import Difficulty 147 148# Components enums 149from .crates.components import ComponentFields 150from .crates.components import ComponentPrivacy 151 152# Entity enums 153from .crates.entity import GatingScope 154from .crates.entity import ObjectiveUIStyle 155from .crates.entity import ValueUIStyle 156 157# Fireteam enums. 158from .crates.fireteams import FireteamActivity 159from .crates.fireteams import FireteamDate 160from .crates.fireteams import FireteamLanguage 161from .crates.fireteams import FireteamPlatform 162 163# Records enums 164from .crates.records import RecordState 165 166__all__ = [mod for mod in dir() if not mod.startswith("_")] # type: ignore
60@attrs.define(auto_exc=True) 61class AiobungieError(RuntimeError): 62 """Base exception class that all other errors inherit from."""
Base exception class that all other errors inherit from.
Inherited Members
- builtins.BaseException
- with_traceback
- args
646@typing.final 647class AmmoType(int, Enum): 648 """AN enum for Detyiny 2 ammo types.""" 649 650 NONE = 0 651 PRIMARY = 1 652 SPECIAL = 2 653 HEAVY = 3
AN enum for Detyiny 2 ammo types.
160@attrs.define(auto_exc=True) 161class BadRequest(HTTPError): 162 """Bad requests exceptions.""" 163 164 url: typing.Optional[typedefs.StrOrURL] 165 """The URL/endpoint caused this error.""" 166 167 body: typing.Any 168 """The response body.""" 169 170 headers: multidict.CIMultiDictProxy[str] 171 """The response headers.""" 172 173 http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)
Bad requests exceptions.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)
Method generated by attrs for class BadRequest.
76@helpers.deprecated("o.2.5", removed_in="0.2.6") 77@attrs.define(auto_exc=True) 78class CharacterError(HTTPError): 79 """Raised when a encountering making a character-based request. 80 81 .. warning:: 82 This is deprecated since 0.2.5 and will be removed in 0.2.6. 83 """
Raised when a encountering making a character-based request.
This is deprecated since 0.2.5 and will be removed in 0.2.6.
701@typing.final 702class ClanMemberType(int, Enum): 703 """An enum for bungie clan member types.""" 704 705 NONE = 0 706 BEGINNER = 1 707 MEMBER = 2 708 ADMIN = 3 709 ACTING_FOUNDER = 4 710 FOUNDER = 5
An enum for bungie clan member types.
477@typing.final 478class Class(int, Enum): 479 """An Enum for Destiny character classes.""" 480 481 TITAN = 0 482 HUNTER = 1 483 WARLOCK = 2 484 UNKNOWN = 3
An Enum for Destiny character classes.
61class Client(traits.ClientApp): 62 """Standard Bungie API client application. 63 64 This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory` 65 and returns `aiobungie.crates` Python object implementations of the responses. 66 67 A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts. 68 69 Parameters 70 ----------- 71 token: `str` 72 Your Bungie's API key or Token from the developer's portal. 73 74 Other Parameters 75 ---------------- 76 rest_client: `aiobungie.interfaces.RESTInterface | None` 77 An optional rest client instance you can pass. 78 If set to `None` then the client will use the default instance. 79 80 Example 81 ------- 82 ```py 83 TOKEN = "SOME_TOKEN" 84 async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client: 85 client = aiobungie.Client(TOKEN, rest_client=rest_client) 86 ``` 87 88 max_retries : `int` 89 The max retries number to retry if the request hit a `5xx` status code. 90 max_ratelimit_retries : `int` 91 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 92 client_secret : `str | None` 93 An optional application client secret, 94 This is only needed if you're fetching OAuth2 tokens with this client. 95 client_id : `int | None` 96 An optional application client id, 97 This is only needed if you're fetching OAuth2 tokens with this client. 98 """ 99 100 __slots__ = ("_rest", "_factory", "_client_secret", "_client_id") 101 102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 rest_client: typing.Optional[interfaces.RESTInterface] = None, 110 max_retries: int = 4, 111 max_ratelimit_retries: int = 3, 112 ) -> None: 113 114 self._client_secret = client_secret 115 self._client_id = client_id 116 117 self._rest = ( 118 rest_client 119 if rest_client is not None 120 else rest_.RESTClient( 121 token, 122 client_secret, 123 client_id, 124 max_retries=max_retries, 125 max_ratelimit_retries=max_ratelimit_retries, 126 ) 127 ) 128 129 self._factory = factory_.Factory(self) 130 131 @property 132 def factory(self) -> factory_.Factory: 133 return self._factory 134 135 @property 136 def rest(self) -> interfaces.RESTInterface: 137 return self._rest 138 139 @property 140 def request(self) -> Client: 141 return copy.copy(self) 142 143 @property 144 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 145 return self._rest.metadata 146 147 def run( 148 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 149 ) -> None: 150 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 151 try: 152 if not loop.is_running(): 153 loop.set_debug(debug) 154 loop.run_until_complete(future) 155 156 except Exception as exc: 157 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 158 159 except KeyboardInterrupt: 160 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 161 return 162 163 finally: 164 if self._rest.is_alive: 165 # Clean up sessions. 166 loop.run_until_complete(self._rest.close()) 167 168 # * User methods. 169 170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp) 189 190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload) 215 216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 ) 239 240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data) 251 252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 ) 283 284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload) 319 320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp) 348 349 # * Destiny 2. 350 351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data) 389 390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp) 429 430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp) 462 463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp) 503 504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ] 534 535 # * Destiny 2 Activities. 536 537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp) 589 590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp) 606 607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp) 639 640 # * Destiny 2 Clans or GroupsV2. 641 642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp) 668 669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp) 709 710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp) 727 728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp) 751 752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ] 790 791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ] 829 830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp) 868 869 async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]: 870 """Fetch the clan banners. 871 872 Returns 873 ------- 874 `collections.Sequence[aiobungie.crates.ClanBanner]` 875 A sequence of the clan banners. 876 """ 877 resp = await self.rest.fetch_clan_banners() 878 879 return self.factory.deserialize_clan_banners(resp) 880 881 # This method is required to be here since it deserialize the clan. 882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp) 919 920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp) 937 938 # * Destiny 2 Entities aka Definitions. 939 940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp) 956 957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp) 973 974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp) 1000 1001 # Fireteams 1002 1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp) 1055 1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp) 1119 1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value] 1147 1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value] 1203 1204 # Friends and social. 1205 1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp) 1228 1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp) 1251 1252 # Applications and Developer portal. 1253 1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp) 1270 1271 # Milestones 1272 1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Standard Bungie API client application.
This client deserialize the REST JSON responses using aiobungie.Factory
and returns aiobungie.crates Python object implementations of the responses.
A aiobungie.RESTClient REST client can also be used alone for low-level concepts.
Parameters
- token (
str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
- rest_client (
aiobungie.interfaces.RESTInterface | None): An optional rest client instance you can pass. If set toNonethen the client will use the default instance.
Example
TOKEN = "SOME_TOKEN"
async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
client = aiobungie.Client(TOKEN, rest_client=rest_client)
max_retries : int
The max retries number to retry if the request hit a 5xx status code.
max_ratelimit_retries : int
The max retries number to retry if the request hit a 429 status code. Defaults to 3.
client_secret : str | None
An optional application client secret,
This is only needed if you're fetching OAuth2 tokens with this client.
client_id : int | None
An optional application client id,
This is only needed if you're fetching OAuth2 tokens with this client.
102 def __init__( 103 self, 104 token: str, 105 /, 106 client_secret: typing.Optional[str] = None, 107 client_id: typing.Optional[int] = None, 108 *, 109 rest_client: typing.Optional[interfaces.RESTInterface] = None, 110 max_retries: int = 4, 111 max_ratelimit_retries: int = 3, 112 ) -> None: 113 114 self._client_secret = client_secret 115 self._client_id = client_id 116 117 self._rest = ( 118 rest_client 119 if rest_client is not None 120 else rest_.RESTClient( 121 token, 122 client_secret, 123 client_id, 124 max_retries=max_retries, 125 max_ratelimit_retries=max_ratelimit_retries, 126 ) 127 ) 128 129 self._factory = factory_.Factory(self)
A mutable mapping storage for the user's needs.
147 def run( 148 self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False 149 ) -> None: 150 loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop() 151 try: 152 if not loop.is_running(): 153 loop.set_debug(debug) 154 loop.run_until_complete(future) 155 156 except Exception as exc: 157 raise RuntimeError(f"Failed to run {future.__qualname__}") from exc 158 159 except KeyboardInterrupt: 160 _LOG.warn("Unexpected Keyboard interrupt. Exiting.") 161 return 162 163 finally: 164 if self._rest.is_alive: 165 # Clean up sessions. 166 loop.run_until_complete(self._rest.close())
Runs a coroutine function until its complete.
This is equivalent to asyncio.get_event_loop().run_until_complete(...)
Parameters
- future (
collections.Coroutine[None, None, None]): A coroutine object. - debug (
bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
await fetch(...)
# Run the coroutine.
client.run(main())
170 async def fetch_current_user_memberships(self, access_token: str, /) -> user.User: 171 """Fetch and return a user object of the bungie net user associated with account. 172 173 .. warning:: 174 This method requires OAuth2 scope and a Bearer access token. 175 176 Parameters 177 ---------- 178 access_token : `str` 179 A valid Bearer access token for the authorization. 180 181 Returns 182 ------- 183 `aiobungie.crates.user.User` 184 A user object includes the Destiny memberships and Bungie.net user. 185 """ 186 resp = await self.rest.fetch_current_user_memberships(access_token) 187 188 return self.factory.deserialize_user(resp)
Fetch and return a user object of the bungie net user associated with account.
This method requires OAuth2 scope and a Bearer access token.
Parameters
- access_token (
str): A valid Bearer access token for the authorization.
Returns
aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
190 async def fetch_bungie_user(self, id: int, /) -> user.BungieUser: 191 """Fetch a Bungie user by their BungieNet id. 192 193 .. note:: 194 This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id` 195 for other memberships. 196 197 Parameters 198 ---------- 199 id: `int` 200 The user id. 201 202 Returns 203 ------- 204 `aiobungie.crates.user.BungieUser` 205 A Bungie user. 206 207 Raises 208 ------ 209 `aiobungie.error.NotFound` 210 The user was not found. 211 """ 212 payload = await self.rest.fetch_bungie_user(id) 213 214 return self.factory.deserialize_bungie_user(payload)
Fetch a Bungie user by their BungieNet id.
This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id
for other memberships.
Parameters
- id (
int): The user id.
Returns
aiobungie.crates.user.BungieUser: A Bungie user.
Raises
aiobungie.NotFound: The user was not found.
216 async def search_users( 217 self, name: str, / 218 ) -> iterators.FlatIterator[user.SearchableDestinyUser]: 219 """Search for players and return all players that matches the same name. 220 221 Parameters 222 ---------- 223 name : `buildins.str` 224 The user name. 225 226 Returns 227 ------- 228 `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]` 229 A sequence of destiny memberships. 230 """ 231 payload = await self.rest.search_users(name) 232 233 return iterators.FlatIterator( 234 [ 235 self.factory.deserialize_searched_user(user) 236 for user in payload["searchResults"] 237 ] 238 )
Search for players and return all players that matches the same name.
Parameters
- name (
buildins.str): The user name.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]: A sequence of destiny memberships.
240 async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]: 241 """Fetch all available user themes. 242 243 Returns 244 ------- 245 `collections.Sequence[aiobungie.crates.user.UserThemes]` 246 A sequence of user themes. 247 """ 248 data = await self.rest.fetch_user_themes() 249 250 return self.factory.deserialize_user_themes(data)
Fetch all available user themes.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
252 async def fetch_hard_types( 253 self, 254 credential: int, 255 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 256 /, 257 ) -> user.HardLinkedMembership: 258 """Gets any hard linked membership given a credential. 259 Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now. 260 Cross Save aware. 261 262 Parameters 263 ---------- 264 credential: `int` 265 A valid SteamID64 266 type: `aiobungie.CredentialType` 267 The credential type. This must not be changed 268 Since its only credential that works "currently" 269 270 Returns 271 ------- 272 `aiobungie.crates.user.HardLinkedMembership` 273 Information about the hard linked data. 274 """ 275 276 payload = await self.rest.fetch_hardlinked_credentials(credential, type) 277 278 return user.HardLinkedMembership( 279 id=int(payload["membershipId"]), 280 type=enums.MembershipType(payload["membershipType"]), 281 cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]), 282 )
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
284 async def fetch_membership_from_id( 285 self, 286 id: int, 287 /, 288 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 289 ) -> user.User: 290 """Fetch Bungie user's memberships from their id. 291 292 Notes 293 ----- 294 * This returns both BungieNet membership and a sequence of the player's DestinyMemberships 295 Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, 296 see `aiobungie.crates.user.DestinyMembership` for more details. 297 * If you only want the bungie user. Consider using `Client.fetch_user` method. 298 299 Parameters 300 ---------- 301 id : `int` 302 The user's id. 303 type : `aiobungie.MembershipType` 304 The user's membership type. 305 306 Returns 307 ------- 308 `aiobungie.crates.User` 309 A Bungie user with their membership types. 310 311 Raises 312 ------ 313 aiobungie.NotFound 314 The requested user was not found. 315 """ 316 payload = await self.rest.fetch_membership_from_id(id, type) 317 318 return self.factory.deserialize_user(payload)
Fetch Bungie user's memberships from their id.
Notes
- This returns both BungieNet membership and a sequence of the player's DestinyMemberships
Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
see
aiobungie.crates.user.DestinyMembershipfor more details. - If you only want the bungie user. Consider using
Client.fetch_usermethod.
Parameters
- id (
int): The user's id. - type (
aiobungie.MembershipType): The user's membership type.
Returns
aiobungie.crates.User: A Bungie user with their membership types.
Raises
- aiobungie.NotFound: The requested user was not found.
320 async def fetch_user_credentials( 321 self, access_token: str, membership_id: int, / 322 ) -> collections.Sequence[user.UserCredentials]: 323 """Fetch an array of credential types attached to the requested account. 324 325 .. note:: 326 This method require OAuth2 Bearer access token. 327 328 Parameters 329 ---------- 330 access_token : `str` 331 The bearer access token associated with the bungie account. 332 membership_id : `int` 333 The id of the membership to return. 334 335 Returns 336 ------- 337 `collections.Sequence[aiobungie.crates.UserCredentials]` 338 A sequence of the attached user credentials. 339 340 Raises 341 ------ 342 `aiobungie.Unauthorized` 343 The access token was wrong or no access token passed. 344 """ 345 resp = await self.rest.fetch_user_credentials(access_token, membership_id) 346 347 return self.factory.deserialize_user_credentials(resp)
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of the attached user credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
351 async def fetch_profile( 352 self, 353 member_id: int, 354 type: typedefs.IntAnd[enums.MembershipType], 355 components: list[enums.ComponentType], 356 auth: typing.Optional[str] = None, 357 ) -> components.Component: 358 """ 359 Fetch a bungie profile passing components to the request. 360 361 Parameters 362 ---------- 363 member_id: `int` 364 The member's id. 365 type: `aiobungie.MembershipType` 366 A valid membership type. 367 components : `list[aiobungie.ComponentType]` 368 List of profile components to collect and return. 369 370 Other Parameters 371 ---------------- 372 auth : `typing.Optional[str]` 373 A Bearer access_token to make the request with. 374 This is optional and limited to components that only requires an Authorization token. 375 376 Returns 377 -------- 378 `aiobungie.crates.Component` 379 A Destiny 2 player profile with its components. 380 Only passed components will be available if they exists. Otherwise they will be `None` 381 382 Raises 383 ------ 384 `aiobungie.MembershipTypeError` 385 The provided membership type was invalid. 386 """ 387 data = await self.rest.fetch_profile(member_id, type, components, auth) 388 return self.factory.deserialize_components(data)
Fetch a bungie profile passing components to the request.
Parameters
- member_id (
int): The member's id. - type (
aiobungie.MembershipType): A valid membership type. - components (
list[aiobungie.ComponentType]): List of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will beNone
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
390 async def fetch_linked_profiles( 391 self, 392 member_id: int, 393 member_type: typedefs.IntAnd[enums.MembershipType], 394 /, 395 *, 396 all: bool = False, 397 ) -> profile.LinkedProfile: 398 """Returns a summary information about all profiles linked to the requested member. 399 400 The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships. 401 402 .. note:: 403 It will only return linked accounts whose linkages you are allowed to view. 404 405 Parameters 406 ---------- 407 member_id : `int` 408 The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. 409 member_type : `aiobungie.MembershipType` 410 The type for the membership whose linked Destiny account you want to return. 411 412 Other Parameters 413 ---------------- 414 all : `bool` 415 If provided and set to `True`, All memberships regardless 416 of whether they're obscured by overrides will be returned, 417 418 If provided and set to `False`, Only available memberships will be returned. 419 The default for this is `False`. 420 421 Returns 422 ------- 423 `aiobungie.crates.profile.LinkedProfile` 424 A linked profile object. 425 """ 426 resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all) 427 428 return self.factory.deserialize_linked_profiles(resp)
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether they're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.crates.profile.LinkedProfile: A linked profile object.
430 async def fetch_player( 431 self, 432 name: str, 433 code: int, 434 /, 435 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 436 ) -> collections.Sequence[user.DestinyMembership]: 437 """Fetch a Destiny 2 player's memberships. 438 439 Parameters 440 ----------- 441 name: `str` 442 The unique Bungie player name. 443 code : `int` 444 The unique Bungie display name code. 445 type: `aiobungie.internal.enums.MembershipType` 446 The player's membership type, e,g. XBOX, STEAM, PSN 447 448 Returns 449 -------- 450 `collections.Sequence[aiobungie.crates.DestinyMembership]` 451 A sequence of the found Destiny 2 player memberships. 452 An empty sequence will be returned if no one found. 453 454 Raises 455 ------ 456 `aiobungie.MembershipTypeError` 457 The provided membership type was invalid. 458 """ 459 resp = await self.rest.fetch_player(name, code, type) 460 461 return self.factory.deserialize_destiny_memberships(resp)
Fetch a Destiny 2 player's memberships.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
collections.Sequence[aiobungie.crates.DestinyMembership]: A sequence of the found Destiny 2 player memberships. An empty sequence will be returned if no one found.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
463 async def fetch_character( 464 self, 465 member_id: int, 466 membership_type: typedefs.IntAnd[enums.MembershipType], 467 character_id: int, 468 components: list[enums.ComponentType], 469 auth: typing.Optional[str] = None, 470 ) -> components.CharacterComponent: 471 """Fetch a Destiny 2 character. 472 473 Parameters 474 ---------- 475 member_id: `int` 476 A valid bungie member id. 477 character_id: `int` 478 The Destiny character id to retrieve. 479 membership_type: `aiobungie.internal.enums.MembershipType` 480 The member's membership type. 481 components: `list[aiobungie.ComponentType]` 482 Multiple arguments of character components to collect and return. 483 484 Other Parameters 485 ---------------- 486 auth : `typing.Optional[str]` 487 A Bearer access_token to make the request with. 488 This is optional and limited to components that only requires an Authorization token. 489 490 Returns 491 ------- 492 `aiobungie.crates.CharacterComponent` 493 A Bungie character component. 494 495 `aiobungie.MembershipTypeError` 496 The provided membership type was invalid. 497 """ 498 resp = await self.rest.fetch_character( 499 member_id, membership_type, character_id, components, auth 500 ) 501 502 return self.factory.deserialize_character_component(resp)
Fetch a Destiny 2 character.
Parameters
- member_id (
int): A valid bungie member id. - character_id (
int): The Destiny character id to retrieve. - membership_type (
aiobungie.MembershipType): The member's membership type. - components (
list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.crates.CharacterComponent: A Bungie character component.aiobungie.MembershipTypeError: The provided membership type was invalid.
504 async def fetch_unique_weapon_history( 505 self, 506 membership_id: int, 507 character_id: int, 508 membership_type: typedefs.IntAnd[enums.MembershipType], 509 ) -> collections.Sequence[activity.ExtendedWeaponValues]: 510 """Fetch details about unique weapon usage for a character. Includes all exotics. 511 512 Parameters 513 ---------- 514 membership_id : `int` 515 The Destiny user membership id. 516 character_id : `int` 517 The character id to retrieve. 518 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 519 The Destiny user's membership type. 520 521 Returns 522 ------- 523 `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]` 524 A sequence of the weapon's extended values. 525 """ 526 resp = await self._rest.fetch_unique_weapon_history( 527 membership_id, character_id, membership_type 528 ) 529 530 return [ 531 self._factory.deserialize_extended_weapon_values(weapon) 532 for weapon in resp["weapons"] 533 ]
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
collections.Sequence[aiobungie.crates.ExtendedWeaponValues]: A sequence of the weapon's extended values.
537 async def fetch_activities( 538 self, 539 member_id: int, 540 character_id: int, 541 mode: typedefs.IntAnd[enums.GameMode], 542 *, 543 membership_type: typedefs.IntAnd[ 544 enums.MembershipType 545 ] = enums.MembershipType.ALL, 546 page: int = 0, 547 limit: int = 250, 548 ) -> iterators.FlatIterator[activity.Activity]: 549 """Fetch a Destiny 2 activity for the specified character id. 550 551 Parameters 552 ---------- 553 member_id: `int` 554 The user id that starts with `4611`. 555 character_id: `int` 556 The id of the character to retrieve the activities for. 557 mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]` 558 This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc. 559 560 Other Parameters 561 ---------------- 562 membership_type: `aiobungie.internal.enums.MembershipType` 563 The Member ship type, if nothing was passed than it will return all. 564 page: int 565 The page number. Default is `0` 566 limit: int 567 Limit the returned result. Default is `250`. 568 569 Returns 570 ------- 571 `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]` 572 An iterator of the player's activities. 573 574 Raises 575 ------ 576 `aiobungie.MembershipTypeError` 577 The provided membership type was invalid. 578 """ 579 resp = await self.rest.fetch_activities( 580 member_id, 581 character_id, 582 mode, 583 membership_type=membership_type, 584 page=page, 585 limit=limit, 586 ) 587 588 return self.factory.deserialize_activities(resp)
Fetch a Destiny 2 activity for the specified character id.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve the activities for. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all. - page (int):
The page number. Default is
0 - limit (int):
Limit the returned result. Default is
250.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
590 async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity: 591 """Fetch a post activity details. 592 593 Parameters 594 ---------- 595 instance_id: `int` 596 The activity instance id. 597 598 Returns 599 ------- 600 `aiobungie.crates.PostActivity` 601 A post activity object. 602 """ 603 resp = await self.rest.fetch_post_activity(instance_id) 604 605 return self.factory.deserialize_post_activity(resp)
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.crates.PostActivity: A post activity object.
607 async def fetch_aggregated_activity_stats( 608 self, 609 character_id: int, 610 membership_id: int, 611 membership_type: typedefs.IntAnd[enums.MembershipType], 612 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 613 """Fetch aggregated activity stats for a character. 614 615 Parameters 616 ---------- 617 character_id: `int` 618 The id of the character to retrieve the activities for. 619 membership_id: `int` 620 The id of the user that started with `4611`. 621 membership_type: `aiobungie.internal.enums.MembershipType` 622 The Member ship type. 623 624 Returns 625 ------- 626 `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]` 627 An iterator of the player's activities. 628 629 Raises 630 ------ 631 `aiobungie.MembershipTypeError` 632 The provided membership type was invalid. 633 """ 634 resp = await self.rest.fetch_aggregated_activity_stats( 635 character_id, membership_id, membership_type 636 ) 637 638 return self.factory.deserialize_aggregated_activities(resp)
Fetch aggregated activity stats for a character.
Parameters
- character_id (
int): The id of the character to retrieve the activities for. - membership_id (
int): The id of the user that started with4611. - membership_type (
aiobungie.MembershipType): The Member ship type.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator of the player's activities.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
642 async def fetch_clan_from_id( 643 self, 644 id: int, 645 /, 646 access_token: typing.Optional[str] = None, 647 ) -> clans.Clan: 648 """Fetch a Bungie Clan by its id. 649 650 Parameters 651 ----------- 652 id: `int` 653 The clan id. 654 655 Returns 656 -------- 657 `aiobungie.crates.Clan` 658 An Bungie clan. 659 660 Raises 661 ------ 662 `aiobungie.NotFound` 663 The clan was not found. 664 """ 665 resp = await self.rest.fetch_clan_from_id(id, access_token) 666 667 return self.factory.deserialize_clan(resp)
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Returns
aiobungie.crates.Clan: An Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
669 async def fetch_clan( 670 self, 671 name: str, 672 /, 673 access_token: typing.Optional[str] = None, 674 *, 675 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 676 ) -> clans.Clan: 677 """Fetch a Clan by its name. 678 This method will return the first clan found with given name. 679 680 Parameters 681 ---------- 682 name: `str` 683 The clan name 684 685 Other Parameters 686 ---------------- 687 access_token : `typing.Optional[str]` 688 An optional access token to make the request with. 689 690 If the token was bound to a member of the clan, 691 This field `aiobungie.crates.Clan.current_user_membership` will be available 692 and will return the membership of the user who made this request. 693 type : `aiobungie.GroupType` 694 The group type, Default is aiobungie.GroupType.CLAN. 695 696 Returns 697 ------- 698 `aiobungie.crates.Clan` 699 A Bungie clan. 700 701 Raises 702 ------ 703 `aiobungie.NotFound` 704 The clan was not found. 705 """ 706 resp = await self.rest.fetch_clan(name, access_token, type=type) 707 708 return self.factory.deserialize_clan(resp)
Fetch a Clan by its name. This method will return the first clan found with given name.
Parameters
- name (
str): The clan name
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.GroupType): The group type, Default is aiobungie.GroupType.CLAN.
Returns
aiobungie.crates.Clan: A Bungie clan.
Raises
aiobungie.NotFound: The clan was not found.
710 async def fetch_clan_conversations( 711 self, clan_id: int, / 712 ) -> collections.Sequence[clans.ClanConversation]: 713 """Fetch the conversations/chat channels of the given clan id. 714 715 Parameters 716 ---------- 717 clan_id : `int` 718 The clan id. 719 720 Returns 721 `collections.Sequence[aiobungie.crates.ClanConversation]` 722 A sequence of the clan chat channels. 723 """ 724 resp = await self.rest.fetch_clan_conversations(clan_id) 725 726 return self.factory.deserialize_clan_conversations(resp)
Fetch the conversations/chat channels of the given clan id.
Parameters
- clan_id (
int): The clan id. - Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of the clan chat channels.
728 async def fetch_clan_admins( 729 self, clan_id: int, / 730 ) -> iterators.FlatIterator[clans.ClanMember]: 731 """Fetch the clan founder and admins. 732 733 Parameters 734 ---------- 735 clan_id : `int` 736 The clan id. 737 738 Returns 739 ------- 740 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 741 An iterator over the found clan admins and founder. 742 743 Raises 744 ------ 745 `aiobungie.NotFound` 746 The requested clan was not found. 747 """ 748 resp = await self.rest.fetch_clan_admins(clan_id) 749 750 return self.factory.deserialize_clan_members(resp)
Fetch the clan founder and admins.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the found clan admins and founder.
Raises
aiobungie.NotFound: The requested clan was not found.
752 async def fetch_groups_for_member( 753 self, 754 member_id: int, 755 member_type: typedefs.IntAnd[enums.MembershipType], 756 /, 757 *, 758 filter: int = 0, 759 group_type: enums.GroupType = enums.GroupType.CLAN, 760 ) -> collections.Sequence[clans.GroupMember]: 761 """Fetch information about the groups that a given member has joined. 762 763 Parameters 764 ---------- 765 member_id : `int` 766 The member's id 767 member_type : `aiobungie.MembershipType` 768 The member's membership type. 769 770 Other Parameters 771 ---------------- 772 filter : `int` 773 Filter apply to list of joined groups. This Default to `0` 774 group_type : `aiobungie.GroupType` 775 The group's type. 776 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 777 778 Returns 779 ------- 780 `collections.Sequence[aiobungie.crates.GroupMember]` 781 A sequence of joined groups for the fetched member. 782 """ 783 resp = await self.rest.fetch_groups_for_member( 784 member_id, member_type, filter=filter, group_type=group_type 785 ) 786 787 return [ 788 self.factory.deserialize_group_member(group) for group in resp["results"] 789 ]
Fetch information about the groups that a given member has joined.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.MembershipType): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.GroupType): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined groups for the fetched member.
791 async def fetch_potential_groups_for_member( 792 self, 793 member_id: int, 794 member_type: typedefs.IntAnd[enums.MembershipType], 795 /, 796 *, 797 filter: int = 0, 798 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 799 ) -> collections.Sequence[clans.GroupMember]: 800 """Fetch the potential groups for a clan member. 801 802 Parameters 803 ---------- 804 member_id : `int` 805 The member's id 806 member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 807 The member's membership type. 808 809 Other Parameters 810 ---------------- 811 filter : `int` 812 Filter apply to list of joined groups. This Default to `0` 813 group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]` 814 The group's type. 815 This is always set to `aiobungie.GroupType.CLAN` and should not be changed. 816 817 Returns 818 ------- 819 `collections.Sequence[aiobungie.crates.GroupMember]` 820 A sequence of joined potential groups for the fetched member. 821 """ 822 resp = await self.rest.fetch_potential_groups_for_member( 823 member_id, member_type, filter=filter, group_type=group_type 824 ) 825 826 return [ 827 self.factory.deserialize_group_member(group) for group in resp["results"] 828 ]
Fetch the potential groups for a clan member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
collections.Sequence[aiobungie.crates.GroupMember]: A sequence of joined potential groups for the fetched member.
830 async def fetch_clan_members( 831 self, 832 clan_id: int, 833 /, 834 *, 835 name: typing.Optional[str] = None, 836 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 837 ) -> iterators.FlatIterator[clans.ClanMember]: 838 """Fetch Bungie clan members. 839 840 Parameters 841 ---------- 842 clan_id : `int` 843 The clans id 844 845 Other Parameters 846 ---------------- 847 name : `typing.Optional[str]` 848 If provided, Only players matching this name will be returned. 849 type : `aiobungie.MembershipType` 850 An optional clan member's membership type. 851 This parameter is used to filter the returned results 852 by the provided membership, For an example XBox memberships only, 853 Otherwise will return all memberships. 854 855 Returns 856 ------- 857 `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]` 858 An iterator over the bungie clan members. 859 860 Raises 861 ------ 862 `aiobungie.NotFound` 863 The clan was not found. 864 """ 865 resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name) 866 867 return self.factory.deserialize_clan_members(resp)
Fetch Bungie clan members.
Parameters
- clan_id (
int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator over the bungie clan members.
Raises
aiobungie.NotFound: The clan was not found.
882 async def kick_clan_member( 883 self, 884 access_token: str, 885 /, 886 group_id: int, 887 membership_id: int, 888 membership_type: typedefs.IntAnd[enums.MembershipType], 889 ) -> clans.Clan: 890 """Kick a member from the clan. 891 892 .. note:: 893 This request requires OAuth2: oauth2: `AdminGroups` scope. 894 895 Parameters 896 ---------- 897 access_token : `str` 898 The bearer access token associated with the bungie account. 899 group_id: `int` 900 The group id. 901 membership_id : `int` 902 The member id to kick. 903 membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]` 904 The member's membership type. 905 906 Returns 907 ------- 908 `aiobungie.crates.clan.Clan` 909 The clan that the member was kicked from. 910 """ 911 resp = await self.rest.kick_clan_member( 912 access_token, 913 group_id=group_id, 914 membership_id=membership_id, 915 membership_type=membership_type, 916 ) 917 918 return self.factory.deserialize_clan(resp)
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.crates.clan.Clan: The clan that the member was kicked from.
920 async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone: 921 """Fetch a Bungie clan's weekly reward state. 922 923 Parameters 924 ---------- 925 clan_id : `int` 926 The clan's id. 927 928 Returns 929 ------- 930 `aiobungie.crates.Milestone` 931 A runtime status of the clan's milestone data. 932 """ 933 934 resp = await self.rest.fetch_clan_weekly_rewards(clan_id) 935 936 return self.factory.deserialize_milestone(resp)
Fetch a Bungie clan's weekly reward state.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.crates.Milestone: A runtime status of the clan's milestone data.
940 async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity: 941 """Fetch a static inventory item entity given a its hash. 942 943 Parameters 944 ---------- 945 hash: `int` 946 Inventory item's hash. 947 948 Returns 949 ------- 950 `aiobungie.crates.InventoryEntity` 951 A bungie inventory item. 952 """ 953 resp = await self.rest.fetch_inventory_item(hash) 954 955 return self.factory.deserialize_inventory_entity(resp)
Fetch a static inventory item entity given a its hash.
Parameters
- hash (
int): Inventory item's hash.
Returns
aiobungie.crates.InventoryEntity: A bungie inventory item.
957 async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity: 958 """Fetch a Destiny objective entity given a its hash. 959 960 Parameters 961 ---------- 962 hash: `int` 963 objective's hash. 964 965 Returns 966 ------- 967 `aiobungie.crates.ObjectiveEntity` 968 An objective entity item. 969 """ 970 resp = await self.rest.fetch_objective_entity(hash) 971 972 return self.factory.deserialize_objective_entity(resp)
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity item.
974 async def search_entities( 975 self, name: str, entity_type: str, *, page: int = 0 976 ) -> iterators.FlatIterator[entity.SearchableEntity]: 977 """Search for Destiny2 entities given a name and its type. 978 979 Parameters 980 ---------- 981 name : `str` 982 The name of the entity, i.e., Thunderlord, One thousand voices. 983 entity_type : `str` 984 The type of the entity, AKA Definition, 985 For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items. 986 987 Other Parameters 988 ---------------- 989 page : `int` 990 An optional page to return. Default to 0. 991 992 Returns 993 ------- 994 `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]` 995 An iterator over the found results matching the provided name. 996 """ 997 resp = await self.rest.search_entities(name, entity_type, page=page) 998 999 return self.factory.deserialize_inventory_results(resp)
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinitionfor emblems, weapons, and other inventory items.
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found results matching the provided name.
1003 async def fetch_fireteams( 1004 self, 1005 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1006 *, 1007 platform: typedefs.IntAnd[ 1008 fireteams.FireteamPlatform 1009 ] = fireteams.FireteamPlatform.ANY, 1010 language: typing.Union[ 1011 fireteams.FireteamLanguage, str 1012 ] = fireteams.FireteamLanguage.ALL, 1013 date_range: int = 0, 1014 page: int = 0, 1015 slots_filter: int = 0, 1016 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1017 """Fetch public Bungie fireteams with open slots. 1018 1019 Parameters 1020 ---------- 1021 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1022 The fireteam activity type. 1023 1024 Other Parameters 1025 ---------------- 1026 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1027 If this is provided. Then the results will be filtered with the given platform. 1028 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1029 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1030 A locale language to filter the used language in that fireteam. 1031 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1032 date_range : `int` 1033 An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`. 1034 page : `int` 1035 The page number. By default its `0` which returns all available activities. 1036 slots_filter : `int` 1037 Filter the returned fireteams based on available slots. Default is `0` 1038 1039 Returns 1040 ------- 1041 `typing.Optional[collections.Sequence[fireteams.Fireteam]]` 1042 A sequence of `aiobungie.crates.Fireteam` or `None`. 1043 """ 1044 1045 resp = await self.rest.fetch_fireteams( 1046 activity_type, 1047 platform=platform, 1048 language=language, 1049 date_range=date_range, 1050 page=page, 1051 slots_filter=slots_filter, 1052 ) 1053 1054 return self.factory.deserialize_fireteams(resp)
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[fireteams.Fireteam]]: A sequence ofaiobungie.crates.FireteamorNone.
1056 async def fetch_avaliable_clan_fireteams( 1057 self, 1058 access_token: str, 1059 group_id: int, 1060 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1061 *, 1062 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1063 language: typing.Union[fireteams.FireteamLanguage, str], 1064 date_range: int = 0, 1065 page: int = 0, 1066 public_only: bool = False, 1067 slots_filter: int = 0, 1068 ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]: 1069 """Fetch a clan's fireteams with open slots. 1070 1071 .. note:: 1072 This method requires OAuth2: ReadGroups scope. 1073 1074 Parameters 1075 ---------- 1076 access_token : `str` 1077 The bearer access token associated with the bungie account. 1078 group_id : `int` 1079 The group/clan id of the fireteam. 1080 activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]` 1081 The fireteam activity type. 1082 1083 Other Parameters 1084 ---------------- 1085 platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]` 1086 If this is provided. Then the results will be filtered with the given platform. 1087 Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms. 1088 language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]` 1089 A locale language to filter the used language in that fireteam. 1090 Defaults to `aiobungie.crates.FireteamLanguage.ALL` 1091 date_range : `int` 1092 An integer to filter the date range of the returned fireteams. Defaults to `0`. 1093 page : `int` 1094 The page number. By default its `0` which returns all available activities. 1095 public_only: `bool` 1096 If set to True, Then only public fireteams will be returned. 1097 slots_filter : `int` 1098 Filter the returned fireteams based on available slots. Default is `0` 1099 1100 Returns 1101 ------- 1102 `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]` 1103 A sequence of fireteams found in the clan. 1104 `None` will be returned if nothing was found. 1105 """ 1106 resp = await self.rest.fetch_avaliable_clan_fireteams( 1107 access_token, 1108 group_id, 1109 activity_type, 1110 platform=platform, 1111 language=language, 1112 date_range=date_range, 1113 page=page, 1114 public_only=public_only, 1115 slots_filter=slots_filter, 1116 ) 1117 1118 return self.factory.deserialize_fireteams(resp)
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
int): An integer to filter the date range of the returned fireteams. Defaults to0. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan.Nonewill be returned if nothing was found.
1120 async def fetch_clan_fireteam( 1121 self, access_token: str, fireteam_id: int, group_id: int 1122 ) -> fireteams.AvailableFireteam: 1123 """Fetch a specific clan fireteam. 1124 1125 .. note:: 1126 This method requires OAuth2: ReadGroups scope. 1127 1128 Parameters 1129 ---------- 1130 access_token : `str` 1131 The bearer access token associated with the bungie account. 1132 group_id : `int` 1133 The group/clan id to fetch the fireteam from. 1134 fireteam_id : `int` 1135 The fireteam id to fetch. 1136 1137 Returns 1138 ------- 1139 `typing.Optional[aiobungie.crates.AvailableFireteam]` 1140 A sequence of available fireteams objects if exists. else `None` will be returned. 1141 """ 1142 resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id) 1143 1144 return self.factory.deserialize_available_fireteams( 1145 resp, no_results=True 1146 ) # type: ignore[return-value]
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
typing.Optional[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1148 async def fetch_my_clan_fireteams( 1149 self, 1150 access_token: str, 1151 group_id: int, 1152 *, 1153 include_closed: bool = True, 1154 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1155 language: typing.Union[fireteams.FireteamLanguage, str], 1156 filtered: bool = True, 1157 page: int = 0, 1158 ) -> collections.Sequence[fireteams.AvailableFireteam]: 1159 """A method that's similar to `fetch_fireteams` but requires OAuth2. 1160 1161 .. note:: 1162 This method requires OAuth2: ReadGroups scope. 1163 1164 Parameters 1165 ---------- 1166 access_token : str 1167 The bearer access token associated with the bungie account. 1168 group_id : int 1169 The group/clan id to fetch. 1170 1171 Other Parameters 1172 ---------------- 1173 include_closed : bool 1174 If provided and set to True, It will also return closed fireteams. 1175 If provided and set to False, It will only return public fireteams. Default is True. 1176 platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform] 1177 If this is provided. Then the results will be filtered with the given platform. 1178 Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms. 1179 language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str] 1180 A locale language to filter the used language in that fireteam. 1181 Defaults to aiobungie.crates.FireteamLanguage.ALL 1182 filtered : bool 1183 If set to True, it will filter by clan. Otherwise not. Default is True. 1184 page : int 1185 The page number. By default its 0 which returns all available activities. 1186 1187 Returns 1188 ------- 1189 `collections.Sequence[aiobungie.crates.AvailableFireteam]` 1190 A sequence of available fireteams objects if exists. else `None` will be returned. 1191 """ 1192 resp = await self.rest.fetch_my_clan_fireteams( 1193 access_token, 1194 group_id, 1195 include_closed=include_closed, 1196 platform=platform, 1197 language=language, 1198 filtered=filtered, 1199 page=page, 1200 ) 1201 1202 return self.factory.deserialize_available_fireteams(resp) # type: ignore[return-value]
A method that's similar to fetch_fireteams but requires OAuth2.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (str): The bearer access token associated with the bungie account.
- group_id (int): The group/clan id to fetch.
Other Parameters
- include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
- platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
- language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
- filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
- page (int): The page number. By default its 0 which returns all available activities.
Returns
collections.Sequence[aiobungie.crates.AvailableFireteam]: A sequence of available fireteams objects if exists. elseNonewill be returned.
1206 async def fetch_friends( 1207 self, access_token: str, / 1208 ) -> collections.Sequence[friends.Friend]: 1209 """Fetch bungie friend list. 1210 1211 .. note:: 1212 This requests OAuth2: ReadUserData scope. 1213 1214 Parameters 1215 ----------- 1216 access_token : `str` 1217 The bearer access token associated with the bungie account. 1218 1219 Returns 1220 ------- 1221 `collections.Sequence[aiobungie.crates.Friend]` 1222 A sequence of the friends associated with that access token. 1223 """ 1224 1225 resp = await self.rest.fetch_friends(access_token) 1226 1227 return self.factory.deserialize_friends(resp)
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of the friends associated with that access token.
1229 async def fetch_friend_requests( 1230 self, access_token: str, / 1231 ) -> friends.FriendRequestView: 1232 """Fetch pending bungie friend requests queue. 1233 1234 .. note:: 1235 This requests OAuth2: ReadUserData scope. 1236 1237 Parameters 1238 ----------- 1239 access_token : `str` 1240 The bearer access token associated with the bungie account. 1241 1242 Returns 1243 ------- 1244 `aiobungie.crates.FriendRequestView` 1245 A friend requests view of that associated access token. 1246 """ 1247 1248 resp = await self.rest.fetch_friend_requests(access_token) 1249 1250 return self.factory.deserialize_friend_requests(resp)
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.crates.FriendRequestView: A friend requests view of that associated access token.
1254 async def fetch_application(self, appid: int, /) -> application.Application: 1255 """Fetch a Bungie application. 1256 1257 Parameters 1258 ----------- 1259 appid: `int` 1260 The application id. 1261 1262 Returns 1263 -------- 1264 `aiobungie.crates.Application` 1265 A Bungie application. 1266 """ 1267 resp = await self.rest.fetch_application(appid) 1268 1269 return self.factory.deserialize_app(resp)
Fetch a Bungie application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.crates.Application: A Bungie application.
1273 async def fetch_public_milestone_content( 1274 self, milestone_hash: int, / 1275 ) -> milestones.MilestoneContent: 1276 """Fetch the milestone content given its hash. 1277 1278 Parameters 1279 ---------- 1280 milestone_hash : `int` 1281 The milestone hash. 1282 1283 Returns 1284 ------- 1285 `aiobungie.crates.milestones.MilestoneContent` 1286 A milestone content object. 1287 """ 1288 resp = await self.rest.fetch_public_milestone_content(milestone_hash) 1289 1290 return self.factory.deserialize_public_milestone_content(resp)
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.crates.milestones.MilestoneContent: A milestone content object.
782@typing.final 783class ClosedReasons(Flag): 784 """A Flags enumeration representing the reasons why a person can't join this user's fireteam.""" 785 786 NONE = 0 787 MATCHMAKING = 1 788 LOADING = 2 789 SOLO = 4 790 """The activity is required to be played solo.""" 791 INTERNAL_REASONS = 8 792 """ 793 The user can't be joined for one of a variety of internal reasons. 794 Basically, the game can't let you join at this time, 795 but for reasons that aren't under the control of this user 796 """ 797 DISALLOWED_BY_GAME_STATE = 16 798 """The user's current activity/quest/other transitory game state is preventing joining.""" 799 OFFLINE = 32768 800 """The user appears offline."""
A Flags enumeration representing the reasons why a person can't join this user's fireteam.
The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user
The user's current activity/quest/other transitory game state is preventing joining.
74@typing.final 75class ComponentFields(enums.Enum): 76 """An enum that provides fields found in a base component response.""" 77 78 PRIVACY = ComponentPrivacy 79 DISABLED = False
An enum that provides fields found in a base component response.
65@typing.final 66class ComponentPrivacy(int, enums.Enum): 67 """An enum the provides privacy settings for profile components.""" 68 69 NONE = 0 70 PUBLIC = 1 71 PRIVATE = 2
An enum the provides privacy settings for profile components.
363@typing.final 364class ComponentType(Enum): 365 """An Enum for Destiny 2 profile Components.""" 366 367 NONE = 0 368 369 PROFILE = 100 370 PROFILE_INVENTORIES = 102 371 PROFILE_CURRENCIES = 103 372 PROFILE_PROGRESSION = 104 373 ALL_PROFILES = ( 374 PROFILE, 375 PROFILE_INVENTORIES, 376 PROFILE_CURRENCIES, 377 PROFILE_PROGRESSION, 378 ) 379 """All profile components.""" 380 381 VENDORS = 400 382 VENDOR_SALES = 402 383 VENDOR_RECEIPTS = 101 384 ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES) 385 """All vendor components.""" 386 387 # Items 388 ITEM_INSTANCES = 300 389 ITEM_OBJECTIVES = 301 390 ITEM_PERKS = 302 391 ITEM_RENDER_DATA = 303 392 ITEM_STATS = 304 393 ITEM_SOCKETS = 305 394 ITEM_TALENT_GRINDS = 306 395 ITEM_PLUG_STATES = 308 396 ITEM_PLUG_OBJECTIVES = 309 397 ITEM_REUSABLE_PLUGS = 310 398 399 ALL_ITEMS = ( 400 ITEM_PLUG_OBJECTIVES, 401 ITEM_PLUG_STATES, 402 ITEM_SOCKETS, 403 ITEM_INSTANCES, 404 ITEM_OBJECTIVES, 405 ITEM_PERKS, 406 ITEM_RENDER_DATA, 407 ITEM_STATS, 408 ITEM_TALENT_GRINDS, 409 ITEM_REUSABLE_PLUGS, 410 ) 411 """All item components.""" 412 413 PLATFORM_SILVER = 105 414 KIOSKS = 500 415 CURRENCY_LOOKUPS = 600 416 PRESENTATION_NODES = 700 417 COLLECTIBLES = 800 418 RECORDS = 900 419 TRANSITORY = 1000 420 METRICS = 1100 421 INVENTORIES = 102 422 STRING_VARIABLES = 1200 423 CRAFTABLES = 1300 424 425 CHARACTERS = 200 426 CHARACTER_INVENTORY = 201 427 CHARECTER_PROGRESSION = 202 428 CHARACTER_RENDER_DATA = 203 429 CHARACTER_ACTIVITIES = 204 430 CHARACTER_EQUIPMENT = 205 431 432 ALL_CHARACTERS = ( 433 CHARACTERS, 434 CHARACTER_INVENTORY, 435 CHARECTER_PROGRESSION, 436 CHARACTER_RENDER_DATA, 437 CHARACTER_ACTIVITIES, 438 CHARACTER_EQUIPMENT, 439 RECORDS, 440 ) 441 """All character components.""" 442 443 ALL = ( 444 *ALL_PROFILES, # type: ignore 445 *ALL_CHARACTERS, # type: ignore 446 *ALL_VENDORS, # type: ignore 447 *ALL_ITEMS, # type: ignore 448 RECORDS, 449 CURRENCY_LOOKUPS, 450 PRESENTATION_NODES, 451 COLLECTIBLES, 452 KIOSKS, 453 METRICS, 454 PLATFORM_SILVER, 455 INVENTORIES, 456 STRING_VARIABLES, 457 TRANSITORY, 458 CRAFTABLES, 459 ) 460 """ALl components included."""
An Enum for Destiny 2 profile Components.
All item components.
All character components.
ALl components included.
664@typing.final 665class CredentialType(int, Enum): 666 """The types of the accounts system supports at bungie.""" 667 668 NONE = 0 669 XUID = 1 670 PSNID = 2 671 WILD = 3 672 FAKE = 4 673 FACEBOOK = 5 674 GOOGLE = 8 675 WINDOWS = 9 676 DEMONID = 10 677 STEAMID = 12 678 BATTLENETID = 14 679 STADIAID = 16 680 TWITCHID = 18
The types of the accounts system supports at bungie.
542@typing.final 543class DamageType(int, Enum): 544 """Enums for Destiny Damage types""" 545 546 NONE = 0 547 KINETIC = 1 548 ARC = 2 549 SOLAR = 3 550 VOID = 4 551 RAID = 5 552 """This is a special damage type reserved for some raid activity encounters.""" 553 STASIS = 6
Enums for Destiny Damage types
This is a special damage type reserved for some raid activity encounters.
65@typing.final 66class Difficulty(int, enums.Enum): 67 """An enum for activities difficulties.""" 68 69 TRIVIAL = 0 70 EASY = 1 71 NORMAL = 2 72 CHALLENGING = 3 73 HARD = 4 74 BRAVE = 5 75 ALMOST_IMPOSSIBLE = 6 76 IMPOSSIBLE = 7
An enum for activities difficulties.
165@typing.final 166class Dungeon(int, Enum): 167 """An Enum for all available Dungeon/Like missions in Destiny 2.""" 168 169 NORMAL_PRESAGE = 2124066889 170 """Normal Presage""" 171 172 MASTER_PRESAGE = 4212753278 173 """Master Presage""" 174 175 HARBINGER = 1738383283 176 """Harbinger""" 177 178 PROPHECY = 4148187374 179 """Prophecy""" 180 181 MASTER_POH = 785700673 182 """Master Pit of Heresy?""" 183 184 LEGEND_POH = 785700678 185 """Legend Pit of Heresy?""" 186 187 POH = 1375089621 188 """Normal Pit of Heresy.""" 189 190 SHATTERED = 2032534090 191 """Shattered Throne""" 192 193 GOA_LEGEND = 4078656646 194 """Grasp of Avarice legend.""" 195 196 GOA_MASTER = 3774021532 197 """Grasp of Avarice master."""
An Enum for all available Dungeon/Like missions in Destiny 2.
77class Enum(__enum.Enum): 78 """Builtin Python enum with extra handlings.""" 79 80 @property 81 def name(self) -> str: # type: ignore[override] 82 return self._name_ 83 84 @property 85 def value(self) -> typing.Any: # type: ignore[override] 86 return self._value_ 87 88 def __str__(self) -> str: 89 return self._name_ 90 91 def __repr__(self) -> str: 92 return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>" 93 94 def __int__(self) -> int: 95 if isinstance(self.value, _ITERABLE): 96 raise TypeError( 97 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 98 ) 99 return int(self.value)
Builtin Python enum with extra handlings.
61class Factory(interfaces.FactoryInterface): 62 """The base deserialization factory class for all aiobungie objects. 63 64 Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them 65 into a `aiobungie.crates` Python classes. 66 """ 67 68 __slots__ = ("_net",) 69 70 def __init__(self, net: traits.Netrunner) -> None: 71 self._net = net 72 73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 ) 96 97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 ) 113 114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") 130 or "", 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload["applicableMembershipTypes"] 138 if "applicableMembershipTypes" in payload 139 ], 140 ) 141 142 def deserialize_destiny_memberships( 143 self, data: typedefs.JSONArray 144 ) -> collections.Sequence[user.DestinyMembership]: 145 return [self.deserialize_destiny_membership(membership) for membership in data] 146 147 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 148 149 primary_membership_id: typing.Optional[int] = None 150 if raw_primary_id := data.get("primaryMembershipId"): 151 primary_membership_id = int(raw_primary_id) 152 153 return user.User( 154 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 155 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 156 primary_membership_id=primary_membership_id, 157 ) 158 159 def deserialize_searched_user( 160 self, payload: typedefs.JSONObject 161 ) -> user.SearchableDestinyUser: 162 name: undefined.UndefinedOr[str] = undefined.Undefined 163 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 164 raw_name 165 ): 166 name = raw_name 167 168 code: typing.Optional[int] = None 169 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 170 code = int(raw_code) 171 172 bungie_id: typing.Optional[int] = None 173 if raw_bungie_id := payload.get("bungieNetMembershipId"): 174 bungie_id = int(raw_bungie_id) 175 176 return user.SearchableDestinyUser( 177 name=name, 178 code=code, 179 bungie_id=bungie_id, 180 memberships=self.deserialize_destiny_memberships( 181 payload["destinyMemberships"] 182 ), 183 ) 184 185 def deserialize_user_credentials( 186 self, payload: typedefs.JSONArray 187 ) -> collections.Sequence[user.UserCredentials]: 188 return [ 189 user.UserCredentials( 190 type=enums.CredentialType(int(creds["credentialType"])), 191 display_name=creds["credentialDisplayName"], 192 is_public=creds["isPublic"], 193 self_as_string=creds.get("credentialAsString", undefined.Undefined), 194 ) 195 for creds in payload 196 ] 197 198 @staticmethod 199 def set_themese_attrs( 200 payload: typedefs.JSONArray, / 201 ) -> typing.Collection[user.UserThemes]: 202 return [ 203 user.UserThemes( 204 id=int(entry["userThemeId"]), 205 name=entry["userThemeName"] 206 if "userThemeName" in entry 207 else undefined.Undefined, 208 description=entry["userThemeDescription"] 209 if "userThemeDescription" in entry 210 else undefined.Undefined, 211 ) 212 for entry in payload 213 ] 214 215 def deserialize_user_themes( 216 self, payload: typedefs.JSONArray 217 ) -> collections.Sequence[user.UserThemes]: 218 return list(self.set_themese_attrs(payload)) 219 220 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 221 222 # This is kinda redundant 223 data = payload 224 225 # This is always outside the details. 226 current_user_map: typing.Optional[ 227 collections.Mapping[str, clans.ClanMember] 228 ] = None 229 if raw_current_user_map := payload.get("currentUserMemberMap"): 230 current_user_map = { 231 membership_type: self.deserialize_clan_member(membership) 232 for membership_type, membership in raw_current_user_map.items() 233 } 234 235 try: 236 data = payload["detail"] 237 except KeyError: 238 pass 239 240 id = data["groupId"] 241 name = data["name"] 242 created_at = data["creationDate"] 243 member_count = data["memberCount"] 244 about = data["about"] 245 motto = data["motto"] 246 is_public = data["isPublic"] 247 banner = assets.Image(str(data["bannerPath"])) 248 avatar = assets.Image(str(data["avatarPath"])) 249 tags = data["tags"] 250 type = data["groupType"] 251 252 features = data["features"] 253 features_obj = clans.ClanFeatures( 254 max_members=features["maximumMembers"], 255 max_membership_types=features["maximumMembershipsOfGroupType"], 256 capabilities=features["capabilities"], 257 membership_types=features["membershipTypes"], 258 invite_permissions=features["invitePermissionOverride"], 259 update_banner_permissions=features["updateBannerPermissionOverride"], 260 update_culture_permissions=features["updateCulturePermissionOverride"], 261 join_level=features["joinLevel"], 262 ) 263 264 information: typedefs.JSONObject = data["clanInfo"] 265 progression: collections.Mapping[int, progressions.Progression] = { 266 int(prog_hash): self.deserialize_progressions(prog) 267 for prog_hash, prog in information["d2ClanProgressions"].items() 268 } 269 270 founder: typedefs.NoneOr[clans.ClanMember] = None 271 if raw_founder := payload.get("founder"): 272 founder = self.deserialize_clan_member(raw_founder) 273 274 return clans.Clan( 275 net=self._net, 276 id=int(id), 277 name=name, 278 type=enums.GroupType(type), 279 created_at=time.clean_date(created_at), 280 member_count=member_count, 281 motto=motto, 282 about=about, 283 is_public=is_public, 284 banner=banner, 285 avatar=avatar, 286 tags=tags, 287 features=features_obj, 288 owner=founder, 289 progressions=progression, 290 call_sign=information["clanCallsign"], 291 banner_data=information["clanBannerData"], 292 chat_security=data["chatSecurity"], 293 conversation_id=int(data["conversationId"]), 294 allow_chat=data["allowChat"], 295 theme=data["theme"], 296 current_user_membership=current_user_map, 297 ) 298 299 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 300 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 301 return clans.ClanMember( 302 net=self._net, 303 last_seen_name=destiny_user.last_seen_name, 304 id=destiny_user.id, 305 name=destiny_user.name, 306 icon=destiny_user.icon, 307 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 308 group_id=int(data["groupId"]), 309 joined_at=time.clean_date(data["joinDate"]), 310 types=destiny_user.types, 311 is_public=destiny_user.is_public, 312 type=destiny_user.type, 313 code=destiny_user.code, 314 is_online=data["isOnline"], 315 crossave_override=destiny_user.crossave_override, 316 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 317 if "bungieNetUserInfo" in data 318 else None, 319 member_type=enums.ClanMemberType(int(data["memberType"])), 320 ) 321 322 def deserialize_clan_members( 323 self, data: typedefs.JSONObject, / 324 ) -> iterators.FlatIterator[clans.ClanMember]: 325 return iterators.FlatIterator( 326 [self.deserialize_clan_member(member) for member in data["results"]] 327 ) 328 329 def deserialize_group_member( 330 self, payload: typedefs.JSONObject 331 ) -> clans.GroupMember: 332 member = payload["member"] 333 return clans.GroupMember( 334 net=self._net, 335 join_date=time.clean_date(member["joinDate"]), 336 group_id=int(member["groupId"]), 337 member_type=enums.ClanMemberType(member["memberType"]), 338 is_online=member["isOnline"], 339 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 340 inactive_memberships=payload.get("areAllMembershipsInactive", None), 341 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 342 group=self.deserialize_clan(payload["group"]), 343 ) 344 345 def _deserialize_clan_conversation( 346 self, payload: typedefs.JSONObject 347 ) -> clans.ClanConversation: 348 return clans.ClanConversation( 349 net=self._net, 350 id=int(payload["conversationId"]), 351 group_id=int(payload["groupId"]), 352 name=( 353 payload["chatName"] 354 if not typedefs.is_unknown(payload["chatName"]) 355 else undefined.Undefined 356 ), 357 chat_enabled=payload["chatEnabled"], 358 security=payload["chatSecurity"], 359 ) 360 361 def deserialize_clan_conversations( 362 self, payload: typedefs.JSONArray 363 ) -> collections.Sequence[clans.ClanConversation]: 364 return [self._deserialize_clan_conversation(conv) for conv in payload] 365 366 def deserialize_app_owner( 367 self, payload: typedefs.JSONObject 368 ) -> application.ApplicationOwner: 369 return application.ApplicationOwner( 370 net=self._net, 371 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 372 id=int(payload["membershipId"]), 373 type=enums.MembershipType(payload["membershipType"]), 374 icon=assets.Image(str(payload["iconPath"])), 375 is_public=payload["isPublic"], 376 code=payload.get("bungieGlobalDisplayNameCode", None), 377 ) 378 379 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 380 return application.Application( 381 id=int(payload["applicationId"]), 382 name=payload["name"], 383 link=payload["link"], 384 status=payload["status"], 385 redirect_url=payload.get("redirectUrl", None), 386 created_at=time.clean_date(str(payload["creationDate"])), 387 published_at=time.clean_date(str(payload["firstPublished"])), 388 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 389 scope=payload.get("scope", undefined.Undefined), 390 ) 391 392 def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character: 393 total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True) 394 return character.Character( 395 net=self._net, 396 id=int(payload["characterId"]), 397 gender=enums.Gender(payload["genderType"]), 398 race=enums.Race(payload["raceType"]), 399 class_type=enums.Class(payload["classType"]), 400 emblem=assets.Image(str(payload["emblemBackgroundPath"])), 401 emblem_icon=assets.Image(str(payload["emblemPath"])), 402 emblem_hash=int(payload["emblemHash"]), 403 last_played=time.clean_date(payload["dateLastPlayed"]), 404 total_played_time=total_time, 405 member_id=int(payload["membershipId"]), 406 member_type=enums.MembershipType(payload["membershipType"]), 407 level=payload["baseCharacterLevel"], 408 title_hash=payload.get("titleRecordHash", None), 409 light=payload["light"], 410 stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()}, 411 ) 412 413 def deserialize_profile( 414 self, payload: typedefs.JSONObject, / 415 ) -> typing.Optional[profile.Profile]: 416 if (raw_profile := payload.get("data")) is None: 417 return None 418 419 payload = raw_profile 420 id = int(payload["userInfo"]["membershipId"]) 421 name = payload["userInfo"]["displayName"] 422 is_public = payload["userInfo"]["isPublic"] 423 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 424 last_played = time.clean_date(str(payload["dateLastPlayed"])) 425 character_ids = [int(cid) for cid in payload["characterIds"]] 426 power_cap = payload["currentSeasonRewardPowerCap"] 427 428 return profile.Profile( 429 id=int(id), 430 name=name, 431 is_public=is_public, 432 type=type, 433 last_played=last_played, 434 character_ids=character_ids, 435 power_cap=power_cap, 436 net=self._net, 437 ) 438 439 def deserialize_profile_item( 440 self, payload: typedefs.JSONObject 441 ) -> profile.ProfileItemImpl: 442 443 instance_id: typing.Optional[int] = None 444 if raw_instance_id := payload.get("itemInstanceId"): 445 instance_id = int(raw_instance_id) 446 447 version_number: typing.Optional[int] = None 448 if raw_version := payload.get("versionNumber"): 449 version_number = int(raw_version) 450 451 transfer_status = enums.TransferStatus(payload["transferStatus"]) 452 453 return profile.ProfileItemImpl( 454 net=self._net, 455 hash=payload["itemHash"], 456 quantity=payload["quantity"], 457 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 458 location=enums.ItemLocation(payload["location"]), 459 bucket=payload["bucketHash"], 460 transfer_status=transfer_status, 461 lockable=payload["lockable"], 462 state=enums.ItemState(payload["state"]), 463 dismantel_permissions=payload["dismantlePermission"], 464 is_wrapper=payload["isWrapper"], 465 instance_id=instance_id, 466 version_number=version_number, 467 ornament_id=payload.get("overrideStyleItemHash"), 468 ) 469 470 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 471 return records.Objective( 472 net=self._net, 473 hash=payload["objectiveHash"], 474 visible=payload["visible"], 475 complete=payload["complete"], 476 completion_value=payload["completionValue"], 477 progress=payload.get("progress"), 478 destination_hash=payload.get("destinationHash"), 479 activity_hash=payload.get("activityHash"), 480 ) 481 482 def deserialize_records( 483 self, 484 payload: typedefs.JSONObject, 485 scores: typing.Optional[records.RecordScores] = None, 486 **nodes: int, 487 ) -> records.Record: 488 objectives: typing.Optional[list[records.Objective]] = None 489 interval_objectives: typing.Optional[list[records.Objective]] = None 490 record_state: typedefs.IntAnd[records.RecordState] 491 492 record_state = records.RecordState(payload["state"]) 493 494 if raw_objs := payload.get("objectives"): 495 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 496 497 if raw_interval_objs := payload.get("intervalObjectives"): 498 interval_objectives = [ 499 self.deserialize_objectives(obj) for obj in raw_interval_objs 500 ] 501 502 return records.Record( 503 scores=scores, 504 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 505 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 506 state=record_state, 507 objectives=objectives, 508 interval_objectives=interval_objectives, 509 redeemed_count=payload.get("intervalsRedeemedCount", 0), 510 completion_times=payload.get("completedCount", None), 511 reward_visibility=payload.get("rewardVisibilty", None), 512 ) 513 514 def deserialize_character_records( 515 self, 516 payload: typedefs.JSONObject, 517 scores: typing.Optional[records.RecordScores] = None, 518 record_hashes: typing.Optional[list[int]] = None, 519 ) -> records.CharacterRecord: 520 521 record = self.deserialize_records(payload, scores) 522 return records.CharacterRecord( 523 scores=scores, 524 categories_node_hash=record.categories_node_hash, 525 seals_node_hash=record.seals_node_hash, 526 state=record.state, 527 objectives=record.objectives, 528 interval_objectives=record.interval_objectives, 529 redeemed_count=payload.get("intervalsRedeemedCount", 0), 530 completion_times=payload.get("completedCount"), 531 reward_visibility=payload.get("rewardVisibilty"), 532 record_hashes=record_hashes or [], 533 ) 534 535 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 536 return character.Dye( 537 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 538 ) 539 540 def deserialize_character_customization( 541 self, payload: typedefs.JSONObject 542 ) -> character.CustomizationOptions: 543 return character.CustomizationOptions( 544 personality=payload["personality"], 545 face=payload["face"], 546 skin_color=payload["skinColor"], 547 lip_color=payload["lipColor"], 548 eye_color=payload["eyeColor"], 549 hair_colors=payload.get("hairColors", []), 550 feature_colors=payload.get("featureColors", []), 551 decal_color=payload["decalColor"], 552 wear_helmet=payload["wearHelmet"], 553 hair_index=payload["hairIndex"], 554 feature_index=payload["featureIndex"], 555 decal_index=payload["decalIndex"], 556 ) 557 558 def deserialize_character_minimal_equipments( 559 self, payload: typedefs.JSONObject 560 ) -> character.MinimalEquipments: 561 dyes = None 562 if raw_dyes := payload.get("dyes"): 563 if raw_dyes: 564 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 565 return character.MinimalEquipments( 566 net=self._net, item_hash=payload["itemHash"], dyes=dyes 567 ) 568 569 def deserialize_character_render_data( 570 self, payload: typedefs.JSONObject, / 571 ) -> character.RenderedData: 572 return character.RenderedData( 573 net=self._net, 574 customization=self.deserialize_character_customization( 575 payload["customization"] 576 ), 577 custom_dyes=[ 578 self.deserialize_character_dye(dye) 579 for dye in payload["customDyes"] 580 if dye 581 ], 582 equipment=[ 583 self.deserialize_character_minimal_equipments(equipment) 584 for equipment in payload["peerView"]["equipment"] 585 ], 586 ) 587 588 def deserialize_available_activity( 589 self, payload: typedefs.JSONObject 590 ) -> activity.AvailableActivity: 591 return activity.AvailableActivity( 592 hash=payload["activityHash"], 593 is_new=payload["isNew"], 594 is_completed=payload["isCompleted"], 595 is_visible=payload["isVisible"], 596 display_level=payload.get("displayLevel"), 597 recommended_light=payload.get("recommendedLight"), 598 difficulty=activity.Difficulty(payload["difficultyTier"]), 599 can_join=payload["canJoin"], 600 can_lead=payload["canLead"], 601 ) 602 603 def deserialize_character_activity( 604 self, payload: typedefs.JSONObject 605 ) -> activity.CharacterActivity: 606 current_mode: typing.Optional[enums.GameMode] = None 607 if raw_current_mode := payload.get("currentActivityModeType"): 608 current_mode = enums.GameMode(raw_current_mode) 609 610 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 611 if raw_current_modes := payload.get("currentActivityModeTypes"): 612 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 613 614 return activity.CharacterActivity( 615 date_started=time.clean_date(payload["dateActivityStarted"]), 616 current_hash=payload["currentActivityHash"], 617 current_mode_hash=payload["currentActivityModeHash"], 618 current_mode=current_mode, 619 current_mode_hashes=payload.get("currentActivityModeHashes"), 620 current_mode_types=current_mode_types, 621 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 622 last_story_hash=payload["lastCompletedStoryHash"], 623 available_activities=[ 624 self.deserialize_available_activity(activity_) 625 for activity_ in payload["availableActivities"] 626 ], 627 ) 628 629 def deserialize_profile_items( 630 self, payload: typedefs.JSONObject, / 631 ) -> list[profile.ProfileItemImpl]: 632 return [self.deserialize_profile_item(item) for item in payload["items"]] 633 634 def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node: 635 return records.Node( 636 state=int(payload["state"]), 637 objective=self.deserialize_objectives(payload["objective"]) 638 if "objective" in payload 639 else None, 640 progress_value=int(payload["progressValue"]), 641 completion_value=int(payload["completionValue"]), 642 record_category_score=int(payload["recordCategoryScore"]) 643 if "recordCategoryScore" in payload 644 else None, 645 ) 646 647 @staticmethod 648 def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible: 649 recent_collectibles: typing.Optional[collections.Collection[int]] = None 650 if raw_recent_collectibles := payload.get("recentCollectibleHashes"): 651 recent_collectibles = [ 652 int(item_hash) for item_hash in raw_recent_collectibles 653 ] 654 655 collectibles: dict[int, int] = {} 656 for item_hash, mapping in payload["collectibles"].items(): 657 collectibles[int(item_hash)] = int(mapping["state"]) 658 659 return items.Collectible( 660 recent_collectibles=recent_collectibles, 661 collectibles=collectibles, 662 collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]), 663 collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]), 664 ) 665 666 @staticmethod 667 def _deserialize_currencies( 668 payload: typedefs.JSONObject, 669 ) -> collections.Sequence[items.Currency]: 670 return [ 671 items.Currency(hash=int(item_hash), amount=int(amount)) 672 for item_hash, amount in payload["itemQuantities"].items() 673 ] 674 675 def deserialize_progressions( 676 self, payload: typedefs.JSONObject 677 ) -> progressions.Progression: 678 return progressions.Progression( 679 hash=int(payload["progressionHash"]), 680 level=int(payload["level"]), 681 cap=int(payload["levelCap"]), 682 daily_limit=int(payload["dailyLimit"]), 683 weekly_limit=int(payload["weeklyLimit"]), 684 current_progress=int(payload["currentProgress"]), 685 daily_progress=int(payload["dailyProgress"]), 686 needed=int(payload["progressToNextLevel"]), 687 next_level=int(payload["nextLevelAt"]), 688 ) 689 690 def _deserialize_factions( 691 self, payload: typedefs.JSONObject 692 ) -> progressions.Factions: 693 progs = self.deserialize_progressions(payload) 694 return progressions.Factions( 695 hash=progs.hash, 696 level=progs.level, 697 cap=progs.cap, 698 daily_limit=progs.daily_limit, 699 weekly_limit=progs.weekly_limit, 700 current_progress=progs.current_progress, 701 daily_progress=progs.daily_progress, 702 needed=progs.needed, 703 next_level=progs.next_level, 704 faction_hash=payload["factionHash"], 705 faction_vendor_hash=payload["factionVendorIndex"], 706 ) 707 708 def _deserialize_milestone_available_quest( 709 self, payload: typedefs.JSONObject 710 ) -> milestones.MilestoneQuest: 711 return milestones.MilestoneQuest( 712 item_hash=payload["questItemHash"], 713 status=self._deserialize_milestone_quest_status(payload["status"]), 714 ) 715 716 def _deserialize_milestone_activity( 717 self, payload: typedefs.JSONObject 718 ) -> milestones.MilestoneActivity: 719 720 phases: typing.Optional[ 721 collections.Sequence[milestones.MilestoneActivityPhase] 722 ] = None 723 if raw_phases := payload.get("phases"): 724 phases = [ 725 milestones.MilestoneActivityPhase( 726 is_completed=obj["complete"], hash=obj["phaseHash"] 727 ) 728 for obj in raw_phases 729 ] 730 731 return milestones.MilestoneActivity( 732 hash=payload["activityHash"], 733 challenges=[ 734 self.deserialize_objectives(obj["objective"]) 735 for obj in payload["challenges"] 736 ], 737 modifier_hashes=payload.get("modifierHashes"), 738 boolean_options=payload.get("booleanActivityOptions"), 739 phases=phases, 740 ) 741 742 def _deserialize_milestone_quest_status( 743 self, payload: typedefs.JSONObject 744 ) -> milestones.QuestStatus: 745 return milestones.QuestStatus( 746 net=self._net, 747 quest_hash=payload["questHash"], 748 step_hash=payload["stepHash"], 749 step_objectives=[ 750 self.deserialize_objectives(objective) 751 for objective in payload["stepObjectives"] 752 ], 753 is_tracked=payload["tracked"], 754 is_completed=payload["completed"], 755 started=payload["started"], 756 item_instance_id=payload["itemInstanceId"], 757 vendor_hash=payload.get("vendorHash"), 758 is_redeemed=payload["redeemed"], 759 ) 760 761 def _deserialize_milestone_rewards( 762 self, payload: typedefs.JSONObject 763 ) -> milestones.MilestoneReward: 764 return milestones.MilestoneReward( 765 category_hash=payload["rewardCategoryHash"], 766 entries=[ 767 milestones.MilestoneRewardEntry( 768 entry_hash=entry["rewardEntryHash"], 769 is_earned=entry["earned"], 770 is_redeemed=entry["redeemed"], 771 ) 772 for entry in payload["entries"] 773 ], 774 ) 775 776 def deserialize_milestone( 777 self, payload: typedefs.JSONObject 778 ) -> milestones.Milestone: 779 start_date: typing.Optional[datetime.datetime] = None 780 if raw_start_date := payload.get("startDate"): 781 start_date = time.clean_date(raw_start_date) 782 783 end_date: typing.Optional[datetime.datetime] = None 784 if raw_end_date := payload.get("endDate"): 785 end_date = time.clean_date(raw_end_date) 786 787 rewards: typing.Optional[ 788 collections.Collection[milestones.MilestoneReward] 789 ] = None 790 if raw_rewards := payload.get("rewards"): 791 rewards = [ 792 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 793 ] 794 795 activities: typing.Optional[ 796 collections.Sequence[milestones.MilestoneActivity] 797 ] = None 798 if raw_activities := payload.get("activities"): 799 activities = [ 800 self._deserialize_milestone_activity(active) 801 for active in raw_activities 802 ] 803 804 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 805 if raw_quests := payload.get("availableQuests"): 806 quests = [ 807 self._deserialize_milestone_available_quest(quest) 808 for quest in raw_quests 809 ] 810 811 vendors: typing.Optional[ 812 collections.Sequence[milestones.MilestoneVendor] 813 ] = None 814 if raw_vendors := payload.get("vendors"): 815 vendors = [ 816 milestones.MilestoneVendor( 817 vendor_hash=vendor["vendorHash"], 818 preview_itemhash=vendor.get("previewItemHash"), 819 ) 820 for vendor in raw_vendors 821 ] 822 823 return milestones.Milestone( 824 hash=payload["milestoneHash"], 825 start_date=start_date, 826 end_date=end_date, 827 order=payload["order"], 828 rewards=rewards, 829 available_quests=quests, 830 activities=activities, 831 vendors=vendors, 832 ) 833 834 def _deserialize_artifact_tiers( 835 self, payload: typedefs.JSONObject 836 ) -> season.ArtifactTier: 837 return season.ArtifactTier( 838 hash=payload["tierHash"], 839 is_unlocked=payload["isUnlocked"], 840 points_to_unlock=payload["pointsToUnlock"], 841 items=[ 842 season.ArtifactTierItem( 843 hash=item["itemHash"], is_active=item["isActive"] 844 ) 845 for item in payload["items"] 846 ], 847 ) 848 849 def deserialize_characters( 850 self, payload: typedefs.JSONObject 851 ) -> collections.Mapping[int, character.Character]: 852 return { 853 int(char_id): self._set_character_attrs(char) 854 for char_id, char in payload["data"].items() 855 } 856 857 def deserialize_character( 858 self, payload: typedefs.JSONObject 859 ) -> character.Character: 860 return self._set_character_attrs(payload) 861 862 def deserialize_character_equipments( 863 self, payload: typedefs.JSONObject 864 ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]: 865 return { 866 int(char_id): self.deserialize_profile_items(item) 867 for char_id, item in payload["data"].items() 868 } 869 870 def deserialize_character_activities( 871 self, payload: typedefs.JSONObject 872 ) -> collections.Mapping[int, activity.CharacterActivity]: 873 return { 874 int(char_id): self.deserialize_character_activity(data) 875 for char_id, data in payload["data"].items() 876 } 877 878 def deserialize_characters_render_data( 879 self, payload: typedefs.JSONObject 880 ) -> collections.Mapping[int, character.RenderedData]: 881 return { 882 int(char_id): self.deserialize_character_render_data(data) 883 for char_id, data in payload["data"].items() 884 } 885 886 def deserialize_character_progressions( 887 self, payload: typedefs.JSONObject 888 ) -> character.CharacterProgression: 889 progressions_ = { 890 int(prog_id): self.deserialize_progressions(prog) 891 for prog_id, prog in payload["progressions"].items() 892 } 893 894 factions = { 895 int(faction_id): self._deserialize_factions(faction) 896 for faction_id, faction in payload["factions"].items() 897 } 898 899 milestones_ = { 900 int(milestone_hash): self.deserialize_milestone(milestone) 901 for milestone_hash, milestone in payload["milestones"].items() 902 } 903 904 uninstanced_item_objectives = { 905 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 906 for item_hash, obj in payload["uninstancedItemObjectives"].items() 907 } 908 909 artifact = payload["seasonalArtifact"] 910 seasonal_artifact = season.CharacterScopedArtifact( 911 hash=artifact["artifactHash"], 912 points_used=artifact["pointsUsed"], 913 reset_count=artifact["resetCount"], 914 tiers=[ 915 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 916 ], 917 ) 918 checklists = payload["checklists"] 919 920 return character.CharacterProgression( 921 progressions=progressions_, 922 factions=factions, 923 checklists=checklists, 924 milestones=milestones_, 925 seasonal_artifact=seasonal_artifact, 926 uninstanced_item_objectives=uninstanced_item_objectives, 927 ) 928 929 def deserialize_character_progressions_mapping( 930 self, payload: typedefs.JSONObject 931 ) -> collections.Mapping[int, character.CharacterProgression]: 932 character_progressions: collections.Mapping[ 933 int, character.CharacterProgression 934 ] = {} 935 for char_id, data in payload["data"].items(): 936 # A little hack to stop mypy complaining about Mapping <-> dict 937 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 938 return character_progressions 939 940 def deserialize_characters_records( 941 self, 942 payload: typedefs.JSONObject, 943 ) -> collections.Mapping[int, records.CharacterRecord]: 944 945 return { 946 int(rec_id): self.deserialize_character_records( 947 rec, record_hashes=payload.get("featuredRecordHashes") 948 ) 949 for rec_id, rec in payload["records"].items() 950 } 951 952 def deserialize_profile_records( 953 self, payload: typedefs.JSONObject 954 ) -> collections.Mapping[int, records.Record]: 955 raw_profile_records = payload["data"] 956 scores = records.RecordScores( 957 current_score=raw_profile_records["score"], 958 legacy_score=raw_profile_records["legacyScore"], 959 lifetime_score=raw_profile_records["lifetimeScore"], 960 ) 961 return { 962 int(record_id): self.deserialize_records( 963 record, 964 scores, 965 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 966 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 967 ) 968 for record_id, record in raw_profile_records["records"].items() 969 } 970 971 def _deserialize_craftable_socket_plug( 972 self, payload: typedefs.JSONObject 973 ) -> items.CraftableSocketPlug: 974 return items.CraftableSocketPlug( 975 item_hash=int(payload["plugItemHash"]), 976 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 977 ) 978 979 def _deserialize_craftable_socket( 980 self, payload: typedefs.JSONObject 981 ) -> items.CraftableSocket: 982 983 plugs: list[items.CraftableSocketPlug] = [] 984 if raw_plug := payload.get("plug"): 985 plugs.extend( 986 self._deserialize_craftable_socket_plug(plug) for plug in raw_plug 987 ) 988 989 return items.CraftableSocket( 990 plug_set_hash=int(payload["plugSetHash"]), plugs=plugs 991 ) 992 993 def _deserialize_craftable_item( 994 self, payload: typedefs.JSONObject 995 ) -> items.CraftableItem: 996 997 return items.CraftableItem( 998 is_visible=payload["visible"], 999 failed_requirement_indexes=payload.get("failedRequirementIndexes", []), 1000 sockets=[ 1001 self._deserialize_craftable_socket(socket) 1002 for socket in payload["sockets"] 1003 ], 1004 ) 1005 1006 def deserialize_craftables_component( 1007 self, payload: typedefs.JSONObject 1008 ) -> components.CraftablesComponent: 1009 return components.CraftablesComponent( 1010 net=self._net, 1011 craftables={ 1012 int(item_id): self._deserialize_craftable_item(item) 1013 for item_id, item in payload["craftables"].items() 1014 if item is not None 1015 }, 1016 crafting_root_node_hash=payload["craftingRootNodeHash"], 1017 ) 1018 1019 def deserialize_components( # noqa: C901 Too complex. 1020 self, payload: typedefs.JSONObject 1021 ) -> components.Component: 1022 1023 profile_: typing.Optional[profile.Profile] = None 1024 if raw_profile := payload.get("profile"): 1025 profile_ = self.deserialize_profile(raw_profile) 1026 1027 profile_progression: typing.Optional[profile.ProfileProgression] = None 1028 if raw_profile_progression := payload.get("profileProgression"): 1029 profile_progression = self.deserialize_profile_progression( 1030 raw_profile_progression 1031 ) 1032 1033 profile_currencies: typing.Optional[ 1034 collections.Sequence[profile.ProfileItemImpl] 1035 ] = None 1036 if raw_profile_currencies := payload.get("profileCurrencies"): 1037 if "data" in raw_profile_currencies: 1038 profile_currencies = self.deserialize_profile_items( 1039 raw_profile_currencies["data"] 1040 ) 1041 1042 profile_inventories: typing.Optional[ 1043 collections.Sequence[profile.ProfileItemImpl] 1044 ] = None 1045 if raw_profile_inventories := payload.get("profileInventory"): 1046 if "data" in raw_profile_inventories: 1047 profile_inventories = self.deserialize_profile_items( 1048 raw_profile_inventories["data"] 1049 ) 1050 1051 profile_records: typing.Optional[ 1052 collections.Mapping[int, records.Record] 1053 ] = None 1054 1055 if raw_profile_records_ := payload.get("profileRecords"): 1056 profile_records = self.deserialize_profile_records(raw_profile_records_) 1057 1058 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1059 if raw_characters := payload.get("characters"): 1060 characters = self.deserialize_characters(raw_characters) 1061 1062 character_records: typing.Optional[ 1063 collections.Mapping[int, records.CharacterRecord] 1064 ] = None 1065 1066 if raw_character_records := payload.get("characterRecords"): 1067 # Had to do it in two steps.. 1068 to_update: typedefs.JSONObject = {} 1069 for _, data in raw_character_records["data"].items(): 1070 for record_id, record in data.items(): 1071 to_update[record_id] = record 1072 1073 character_records = { 1074 int(rec_id): self.deserialize_character_records( 1075 rec, record_hashes=to_update.get("featuredRecordHashes") 1076 ) 1077 for rec_id, rec in to_update["records"].items() 1078 } 1079 1080 character_equipments: typing.Optional[ 1081 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1082 ] = None 1083 if raw_character_equips := payload.get("characterEquipment"): 1084 character_equipments = self.deserialize_character_equipments( 1085 raw_character_equips 1086 ) 1087 1088 character_inventories: typing.Optional[ 1089 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1090 ] = None 1091 if raw_character_inventories := payload.get("characterInventories"): 1092 if "data" in raw_character_inventories: 1093 character_inventories = self.deserialize_character_equipments( 1094 raw_character_inventories 1095 ) 1096 1097 character_activities: typing.Optional[ 1098 collections.Mapping[int, activity.CharacterActivity] 1099 ] = None 1100 if raw_char_acts := payload.get("characterActivities"): 1101 character_activities = self.deserialize_character_activities(raw_char_acts) 1102 1103 character_render_data: typing.Optional[ 1104 collections.Mapping[int, character.RenderedData] 1105 ] = None 1106 if raw_character_render_data := payload.get("characterRenderData"): 1107 character_render_data = self.deserialize_characters_render_data( 1108 raw_character_render_data 1109 ) 1110 1111 character_progressions: typing.Optional[ 1112 collections.Mapping[int, character.CharacterProgression] 1113 ] = None 1114 1115 if raw_character_progressions := payload.get("characterProgressions"): 1116 character_progressions = self.deserialize_character_progressions_mapping( 1117 raw_character_progressions 1118 ) 1119 1120 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1121 if raw_profile_string_vars := payload.get("profileStringVariables"): 1122 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1123 1124 character_string_vars: typing.Optional[ 1125 collections.Mapping[int, collections.Mapping[int, int]] 1126 ] = None 1127 if raw_character_string_vars := payload.get("characterStringVariables"): 1128 character_string_vars = { 1129 int(char_id): data["integerValuesByHash"] 1130 for char_id, data in raw_character_string_vars["data"].items() 1131 } 1132 1133 metrics: typing.Optional[ 1134 collections.Sequence[ 1135 collections.Mapping[ 1136 int, tuple[bool, typing.Optional[records.Objective]] 1137 ] 1138 ] 1139 ] = None 1140 root_node_hash: typing.Optional[int] = None 1141 1142 if raw_metrics := payload.get("metrics"): 1143 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1144 metrics = [ 1145 { 1146 int(metrics_hash): ( 1147 data["invisible"], 1148 self.deserialize_objectives(data["objectiveProgress"]) 1149 if "objectiveProgress" in data 1150 else None, 1151 ) 1152 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1153 } 1154 ] 1155 transitory: typing.Optional[fireteams.FireteamParty] = None 1156 if raw_transitory := payload.get("profileTransitoryData"): 1157 if "data" in raw_transitory: 1158 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1159 1160 item_components: typing.Optional[components.ItemsComponent] = None 1161 if raw_item_components := payload.get("itemComponents"): 1162 item_components = self.deserialize_items_component(raw_item_components) 1163 1164 profile_plugsets: typing.Optional[ 1165 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1166 ] = None 1167 1168 if raw_profile_plugs := payload.get("profilePlugSets"): 1169 profile_plugsets = { 1170 int(index): [self.deserialize_plug_item_state(state) for state in data] 1171 for index, data in raw_profile_plugs["data"]["plugs"].items() 1172 } 1173 1174 character_plugsets: typing.Optional[ 1175 collections.Mapping[ 1176 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1177 ] 1178 ] = None 1179 if raw_char_plugsets := payload.get("characterPlugSets"): 1180 character_plugsets = { 1181 int(char_id): { 1182 int(index): [ 1183 self.deserialize_plug_item_state(state) for state in data 1184 ] 1185 for index, data in inner["plugs"].items() 1186 } 1187 for char_id, inner in raw_char_plugsets["data"].items() 1188 } 1189 1190 character_collectibles: typing.Optional[ 1191 collections.Mapping[int, items.Collectible] 1192 ] = None 1193 if raw_character_collectibles := payload.get("characterCollectibles"): 1194 character_collectibles = { 1195 int(char_id): self._deserialize_collectible(data) 1196 for char_id, data in raw_character_collectibles["data"].items() 1197 } 1198 1199 profile_collectibles: typing.Optional[items.Collectible] = None 1200 if raw_profile_collectibles := payload.get("profileCollectibles"): 1201 profile_collectibles = self._deserialize_collectible( 1202 raw_profile_collectibles["data"] 1203 ) 1204 1205 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1206 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1207 profile_nodes = { 1208 int(node_hash): self._deserialize_node(node) 1209 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1210 } 1211 1212 character_nodes: typing.Optional[ 1213 collections.Mapping[int, collections.Mapping[int, records.Node]] 1214 ] = None 1215 if raw_character_nodes := payload.get("characterPresentationNodes"): 1216 character_nodes = { 1217 int(char_id): { 1218 int(node_hash): self._deserialize_node(node) 1219 for node_hash, node in each_character["nodes"].items() 1220 } 1221 for char_id, each_character in raw_character_nodes["data"].items() 1222 } 1223 1224 platform_silver: typing.Optional[ 1225 collections.Mapping[str, profile.ProfileItemImpl] 1226 ] = None 1227 if raw_platform_silver := payload.get("platformSilver"): 1228 if "data" in raw_platform_silver: 1229 platform_silver = { 1230 platform_name: self.deserialize_profile_item(item) 1231 for platform_name, item in raw_platform_silver["data"][ 1232 "platformSilver" 1233 ].items() 1234 } 1235 1236 character_currency_lookups: typing.Optional[ 1237 collections.Mapping[int, collections.Sequence[items.Currency]] 1238 ] = None 1239 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1240 if "data" in raw_char_lookups: 1241 character_currency_lookups = { 1242 int(char_id): self._deserialize_currencies(currencie) 1243 for char_id, currencie in raw_char_lookups["data"].items() 1244 } 1245 1246 character_craftables: typing.Optional[ 1247 collections.Mapping[int, components.CraftablesComponent] 1248 ] = None 1249 if raw_character_craftables := payload.get("characterCraftables"): 1250 1251 if "data" in raw_character_craftables: 1252 character_craftables = { 1253 int(char_id): self.deserialize_craftables_component(craftable) 1254 for char_id, craftable in raw_character_craftables["data"].items() 1255 } 1256 1257 return components.Component( 1258 profiles=profile_, 1259 profile_progression=profile_progression, 1260 profile_currencies=profile_currencies, 1261 profile_inventories=profile_inventories, 1262 profile_records=profile_records, 1263 characters=characters, 1264 character_records=character_records, 1265 character_equipments=character_equipments, 1266 character_inventories=character_inventories, 1267 character_activities=character_activities, 1268 character_render_data=character_render_data, 1269 character_progressions=character_progressions, 1270 profile_string_variables=profile_string_vars, 1271 character_string_variables=character_string_vars, 1272 metrics=metrics, 1273 root_node_hash=root_node_hash, 1274 transitory=transitory, 1275 item_components=item_components, 1276 profile_plugsets=profile_plugsets, 1277 character_plugsets=character_plugsets, 1278 character_collectibles=character_collectibles, 1279 profile_collectibles=profile_collectibles, 1280 profile_nodes=profile_nodes, 1281 character_nodes=character_nodes, 1282 platform_silver=platform_silver, 1283 character_currency_lookups=character_currency_lookups, 1284 character_craftables=character_craftables, 1285 ) 1286 1287 def deserialize_items_component( 1288 self, payload: typedefs.JSONObject 1289 ) -> components.ItemsComponent: 1290 instances: typing.Optional[ 1291 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1292 ] = None 1293 if raw_instances := payload.get("instances"): 1294 instances = [ 1295 { 1296 int(ins_id): self.deserialize_instanced_item(item) 1297 for ins_id, item in raw_instances["data"].items() 1298 } 1299 ] 1300 1301 render_data: typing.Optional[ 1302 collections.Mapping[int, tuple[bool, dict[int, int]]] 1303 ] = None 1304 if raw_render_data := payload.get("renderData"): 1305 render_data = { 1306 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1307 for ins_id, data in raw_render_data["data"].items() 1308 } 1309 1310 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1311 if raw_stats := payload.get("stats"): 1312 builder: collections.Mapping[int, items.ItemStatsView] = {} 1313 for ins_id, stat in raw_stats["data"].items(): 1314 for _, items_ in stat.items(): 1315 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1316 stats = builder 1317 1318 sockets: typing.Optional[ 1319 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1320 ] = None 1321 if raw_sockets := payload.get("sockets"): 1322 sockets = { 1323 int(ins_id): [ 1324 self.deserialize_item_socket(socket) for socket in item["sockets"] 1325 ] 1326 for ins_id, item in raw_sockets["data"].items() 1327 } 1328 1329 objeectives: typing.Optional[ 1330 collections.Mapping[int, collections.Sequence[records.Objective]] 1331 ] = None 1332 if raw_objectives := payload.get("objectives"): 1333 objeectives = { 1334 int(ins_id): [self.deserialize_objectives(objective)] 1335 for ins_id, data in raw_objectives["data"].items() 1336 for objective in data["objectives"] 1337 } 1338 1339 perks: typing.Optional[ 1340 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1341 ] = None 1342 if raw_perks := payload.get("perks"): 1343 perks = { 1344 int(ins_id): [ 1345 self.deserialize_item_perk(perk) for perk in item["perks"] 1346 ] 1347 for ins_id, item in raw_perks["data"].items() 1348 } 1349 1350 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1351 if raw_plug_states := payload.get("plugStates"): 1352 pending_states: list[items.PlugItemState] = [] 1353 for _, plug in raw_plug_states["data"].items(): 1354 pending_states.append(self.deserialize_plug_item_state(plug)) 1355 plug_states = pending_states 1356 1357 reusable_plugs: typing.Optional[ 1358 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1359 ] = None 1360 if raw_re_plugs := payload.get("reusablePlugs"): 1361 reusable_plugs = { 1362 int(ins_id): [ 1363 self.deserialize_plug_item_state(state) for state in inner 1364 ] 1365 for ins_id, plug in raw_re_plugs["data"].items() 1366 for inner in list(plug["plugs"].values()) 1367 } 1368 1369 plug_objectives: typing.Optional[ 1370 collections.Mapping[ 1371 int, collections.Mapping[int, collections.Collection[records.Objective]] 1372 ] 1373 ] = None 1374 if raw_plug_objectives := payload.get("plugObjectives"): 1375 plug_objectives = { 1376 int(ins_id): { 1377 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1378 for obj_hash, objs in inner["objectivesPerPlug"].items() 1379 } 1380 for ins_id, inner in raw_plug_objectives["data"].items() 1381 } 1382 1383 return components.ItemsComponent( 1384 sockets=sockets, 1385 stats=stats, 1386 render_data=render_data, 1387 instances=instances, 1388 objectives=objeectives, 1389 perks=perks, 1390 plug_states=plug_states, 1391 reusable_plugs=reusable_plugs, 1392 plug_objectives=plug_objectives, 1393 ) 1394 1395 def deserialize_character_component( # type: ignore[call-arg] 1396 self, payload: typedefs.JSONObject 1397 ) -> components.CharacterComponent: 1398 1399 character_: typing.Optional[character.Character] = None 1400 if raw_singuler_character := payload.get("character"): 1401 character_ = self.deserialize_character(raw_singuler_character["data"]) 1402 1403 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1404 if raw_inventory := payload.get("inventory"): 1405 if "data" in raw_inventory: 1406 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1407 1408 activities: typing.Optional[activity.CharacterActivity] = None 1409 if raw_activities := payload.get("activities"): 1410 activities = self.deserialize_character_activity(raw_activities["data"]) 1411 1412 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1413 if raw_equipments := payload.get("equipment"): 1414 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1415 1416 progressions_: typing.Optional[character.CharacterProgression] = None 1417 if raw_progressions := payload.get("progressions"): 1418 progressions_ = self.deserialize_character_progressions( 1419 raw_progressions["data"] 1420 ) 1421 1422 render_data: typing.Optional[character.RenderedData] = None 1423 if raw_render_data := payload.get("renderData"): 1424 render_data = self.deserialize_character_render_data( 1425 raw_render_data["data"] 1426 ) 1427 1428 character_records: typing.Optional[ 1429 collections.Mapping[int, records.CharacterRecord] 1430 ] = None 1431 if raw_char_records := payload.get("records"): 1432 character_records = self.deserialize_characters_records( 1433 raw_char_records["data"] 1434 ) 1435 1436 item_components: typing.Optional[components.ItemsComponent] = None 1437 if raw_item_components := payload.get("itemComponents"): 1438 item_components = self.deserialize_items_component(raw_item_components) 1439 1440 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1441 if raw_nodes := payload.get("presentationNodes"): 1442 nodes = { 1443 int(node_hash): self._deserialize_node(node) 1444 for node_hash, node in raw_nodes["data"]["nodes"].items() 1445 } 1446 1447 collectibles: typing.Optional[items.Collectible] = None 1448 if raw_collectibles := payload.get("collectibles"): 1449 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1450 1451 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1452 if raw_currencies := payload.get("currencyLookups"): 1453 if "data" in raw_currencies: 1454 currency_lookups = self._deserialize_currencies(raw_currencies) 1455 1456 return components.CharacterComponent( 1457 activities=activities, 1458 equipment=equipment, 1459 inventory=inventory, 1460 progressions=progressions_, 1461 render_data=render_data, 1462 character=character_, 1463 character_records=character_records, 1464 profile_records=None, 1465 item_components=item_components, 1466 currency_lookups=currency_lookups, 1467 collectibles=collectibles, 1468 nodes=nodes, 1469 ) 1470 1471 def _set_entity_attrs( 1472 self, payload: typedefs.JSONObject, *, key: str = "displayProperties" 1473 ) -> entity.Entity: 1474 1475 name: undefined.UndefinedOr[str] = undefined.Undefined 1476 description: undefined.UndefinedOr[str] = undefined.Undefined 1477 1478 if properties := payload[key]: 1479 if (raw_name := properties["name"]) is not typedefs.Unknown: 1480 name = raw_name 1481 1482 if ( 1483 raw_description := properties["description"] 1484 ) and not typedefs.is_unknown(raw_description): 1485 description = raw_description 1486 1487 return entity.Entity( 1488 net=self._net, 1489 hash=payload["hash"], 1490 index=payload["index"], 1491 name=name, 1492 description=description, 1493 has_icon=properties["hasIcon"], 1494 icon=assets.Image(properties["icon"] if "icon" in properties else None), 1495 ) 1496 1497 def deserialize_inventory_results( 1498 self, payload: typedefs.JSONObject 1499 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1500 suggested_words: list[str] = payload["suggestedWords"] 1501 1502 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1503 return s if not typedefs.is_unknown(s) else undefined.Undefined 1504 1505 return iterators.FlatIterator( 1506 [ 1507 entity.SearchableEntity( 1508 net=self._net, 1509 hash=data["hash"], 1510 entity_type=data["entityType"], 1511 weight=data["weight"], 1512 suggested_words=suggested_words, 1513 name=data["displayProperties"]["name"], 1514 has_icon=data["displayProperties"]["hasIcon"], 1515 description=_check_unknown( 1516 data["displayProperties"]["description"] 1517 ), 1518 icon=assets.Image(data["displayProperties"]["icon"]), 1519 ) 1520 for data in payload["results"]["results"] 1521 ] 1522 ) 1523 1524 def _deserialize_inventory_item_objects( 1525 self, payload: typedefs.JSONObject 1526 ) -> entity.InventoryEntityObjects: 1527 return entity.InventoryEntityObjects( 1528 action=payload.get("action"), 1529 set_data=payload.get("setData"), 1530 stats=payload.get("stats"), 1531 equipping_block=payload.get("equippingBlock"), 1532 translation_block=payload.get("translationBlock"), 1533 preview=payload.get("preview"), 1534 quality=payload.get("quality"), 1535 value=payload.get("value"), 1536 source_data=payload.get("sourceData"), 1537 objectives=payload.get("objectives"), 1538 plug=payload.get("plug"), 1539 metrics=payload.get("metrics"), 1540 gearset=payload.get("gearset"), 1541 sack=payload.get("sack"), 1542 sockets=payload.get("sockets"), 1543 summary=payload.get("summary"), 1544 talent_gird=payload.get("talentGrid"), 1545 investments_stats=payload.get("investmentStats"), 1546 perks=payload.get("perks"), 1547 animations=payload.get("animations", []), 1548 links=payload.get("links", []), 1549 ) 1550 1551 def deserialize_inventory_entity( # noqa: C901 Too complex. 1552 self, payload: typedefs.JSONObject, / 1553 ) -> entity.InventoryEntity: 1554 1555 props = self._set_entity_attrs(payload) 1556 objects = self._deserialize_inventory_item_objects(payload) 1557 1558 collectible_hash: typing.Optional[int] = None 1559 if raw_collectible_hash := payload.get("collectibleHash"): 1560 collectible_hash = int(raw_collectible_hash) 1561 1562 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1563 if raw_second_icon := payload.get("secondaryIcon"): 1564 secondary_icon = assets.Image(raw_second_icon) 1565 1566 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1567 if raw_second_overlay := payload.get("secondaryOverlay"): 1568 secondary_overlay = assets.Image(raw_second_overlay) 1569 1570 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1571 if raw_second_special := payload.get("secondarySpecial"): 1572 secondary_special = assets.Image(raw_second_special) 1573 1574 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1575 if raw_screenshot := payload.get("screenshot"): 1576 screenshot = assets.Image(raw_screenshot) 1577 1578 watermark_icon: typing.Optional[assets.Image] = None 1579 if raw_watermark_icon := payload.get("iconWatermark"): 1580 watermark_icon = assets.Image(raw_watermark_icon) 1581 1582 watermark_shelved: typing.Optional[assets.Image] = None 1583 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1584 watermark_shelved = assets.Image(raw_watermark_shelved) 1585 1586 about: undefined.UndefinedOr[str] = undefined.Undefined 1587 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1588 raw_about 1589 ): 1590 about = raw_about 1591 1592 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1593 if ( 1594 raw_ui_style := payload.get("uiItemDisplayStyle") 1595 ) and not typedefs.is_unknown(raw_ui_style): 1596 ui_item_style = raw_ui_style 1597 1598 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1599 if ( 1600 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1601 ) and not typedefs.is_unknown(raw_tier_and_name): 1602 tier_and_name = raw_tier_and_name 1603 1604 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1605 if ( 1606 raw_type_name := payload.get("itemTypeDisplayName") 1607 ) and not typedefs.is_unknown(raw_type_name): 1608 type_name = raw_type_name 1609 1610 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1611 if ( 1612 raw_display_source := payload.get("displaySource") 1613 ) and not typedefs.is_unknown(raw_display_source): 1614 display_source = raw_display_source 1615 1616 lorehash: typing.Optional[int] = None 1617 if raw_lore_hash := payload.get("loreHash"): 1618 lorehash = int(raw_lore_hash) 1619 1620 summary_hash: typing.Optional[int] = None 1621 if raw_summary_hash := payload.get("summaryItemHash"): 1622 summary_hash = raw_summary_hash 1623 1624 breaker_type_hash: typing.Optional[int] = None 1625 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1626 breaker_type_hash = int(raw_breaker_type_hash) 1627 1628 damage_types: typing.Optional[collections.Sequence[int]] = None 1629 if raw_damage_types := payload.get("damageTypes"): 1630 damage_types = [int(type_) for type_ in raw_damage_types] 1631 1632 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1633 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1634 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1635 1636 default_damagetype_hash: typing.Optional[int] = None 1637 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1638 default_damagetype_hash = int(raw_defaultdmg_hash) 1639 1640 emblem_objective_hash: typing.Optional[int] = None 1641 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1642 emblem_objective_hash = int(raw_emblem_obj_hash) 1643 1644 tier_type: typing.Optional[enums.TierType] = None 1645 tier: typing.Optional[enums.ItemTier] = None 1646 bucket_hash: typing.Optional[int] = None 1647 recovery_hash: typing.Optional[int] = None 1648 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1649 isinstance_item: bool = False 1650 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1651 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1652 suppress_expiration: bool = False 1653 max_stack_size: typing.Optional[int] = None 1654 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1655 1656 if inventory := payload.get("inventory"): 1657 tier_type = enums.TierType(int(inventory["tierType"])) 1658 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1659 bucket_hash = int(inventory["bucketTypeHash"]) 1660 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1661 tier_name = inventory["tierTypeName"] 1662 isinstance_item = inventory["isInstanceItem"] 1663 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1664 max_stack_size = int(inventory["maxStackSize"]) 1665 1666 try: 1667 stack_label = inventory["stackUniqueLabel"] 1668 except KeyError: 1669 pass 1670 1671 return entity.InventoryEntity( 1672 net=self._net, 1673 collectible_hash=collectible_hash, 1674 name=props.name, 1675 about=about, 1676 emblem_objective_hash=emblem_objective_hash, 1677 suppress_expiration=suppress_expiration, 1678 max_stack_size=max_stack_size, 1679 stack_label=stack_label, 1680 tier=tier, 1681 tier_type=tier_type, 1682 tier_name=tier_name, 1683 bucket_hash=bucket_hash, 1684 recovery_bucket_hash=recovery_hash, 1685 isinstance_item=isinstance_item, 1686 expire_in_orbit_message=expire_in_orbit_message, 1687 expiration_tooltip=expire_tool_tip, 1688 lore_hash=lorehash, 1689 type_and_tier_name=tier_and_name, 1690 summary_hash=summary_hash, 1691 ui_display_style=ui_item_style, 1692 type_name=type_name, 1693 breaker_type_hash=breaker_type_hash, 1694 description=props.description, 1695 display_source=display_source, 1696 hash=props.hash, 1697 damage_types=damage_types, 1698 index=props.index, 1699 icon=props.icon, 1700 has_icon=props.has_icon, 1701 screenshot=screenshot, 1702 watermark_icon=watermark_icon, 1703 watermark_shelved=watermark_shelved, 1704 secondary_icon=secondary_icon, 1705 secondary_overlay=secondary_overlay, 1706 secondary_special=secondary_special, 1707 type=enums.ItemType(int(payload["itemType"])), 1708 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1709 trait_ids=[trait for trait in payload.get("traitIds", [])], 1710 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1711 item_class=enums.Class(int(payload["classType"])), 1712 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1713 breaker_type=int(payload["breakerType"]), 1714 default_damagetype=int(payload["defaultDamageType"]), 1715 default_damagetype_hash=default_damagetype_hash, 1716 damagetype_hashes=damagetype_hashes, 1717 tooltip_notifications=payload["tooltipNotifications"], 1718 not_transferable=payload["nonTransferrable"], 1719 allow_actions=payload["allowActions"], 1720 is_equippable=payload["equippable"], 1721 objects=objects, 1722 background_colors=payload.get("backgroundColor", {}), 1723 season_hash=payload.get("seasonHash"), 1724 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1725 ) 1726 1727 def deserialize_objective_entity( 1728 self, payload: typedefs.JSONObject, / 1729 ) -> entity.ObjectiveEntity: 1730 props = self._set_entity_attrs(payload) 1731 return entity.ObjectiveEntity( 1732 net=self._net, 1733 hash=props.hash, 1734 index=props.index, 1735 description=props.description, 1736 name=props.name, 1737 has_icon=props.has_icon, 1738 icon=props.icon, 1739 unlock_value_hash=payload["unlockValueHash"], 1740 completion_value=payload["completionValue"], 1741 scope=entity.GatingScope(int(payload["scope"])), 1742 location_hash=payload["locationHash"], 1743 allowed_negative_value=payload["allowNegativeValue"], 1744 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1745 counting_downward=payload["isCountingDownward"], 1746 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1747 progress_description=payload["progressDescription"], 1748 perks=payload["perks"], 1749 stats=payload["stats"], 1750 minimum_visibility=payload["minimumVisibilityThreshold"], 1751 allow_over_completion=payload["allowOvercompletion"], 1752 show_value_style=payload["showValueOnComplete"], 1753 display_only_objective=payload["isDisplayOnlyObjective"], 1754 complete_value_style=entity.ValueUIStyle( 1755 int(payload["completedValueStyle"]) 1756 ), 1757 progress_value_style=entity.ValueUIStyle( 1758 int(payload["inProgressValueStyle"]) 1759 ), 1760 ui_label=payload["uiLabel"], 1761 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1762 ) 1763 1764 def _deserialize_activity_values( 1765 self, payload: typedefs.JSONObject, / 1766 ) -> activity.ActivityValues: 1767 team: typing.Optional[int] = None 1768 if raw_team := payload.get("team"): 1769 team = raw_team["basic"]["value"] 1770 return activity.ActivityValues( 1771 assists=payload["assists"]["basic"]["value"], 1772 deaths=payload["deaths"]["basic"]["value"], 1773 kills=payload["kills"]["basic"]["value"], 1774 is_completed=bool(payload["completed"]["basic"]["value"]), 1775 opponents_defeated=payload["opponentsDefeated"]["basic"]["value"], 1776 efficiency=payload["efficiency"]["basic"]["value"], 1777 kd_ratio=payload["killsDeathsRatio"]["basic"]["value"], 1778 kd_assists=payload["killsDeathsAssists"]["basic"]["value"], 1779 score=payload["score"]["basic"]["value"], 1780 duration=payload["activityDurationSeconds"]["basic"]["displayValue"], 1781 team=team, 1782 completion_reason=payload["completionReason"]["basic"]["displayValue"], 1783 fireteam_id=payload["fireteamId"]["basic"]["value"], 1784 start_seconds=payload["startSeconds"]["basic"]["value"], 1785 played_time=payload["timePlayedSeconds"]["basic"]["displayValue"], 1786 player_count=payload["playerCount"]["basic"]["value"], 1787 team_score=payload["teamScore"]["basic"]["value"], 1788 ) 1789 1790 def deserialize_activity( 1791 self, 1792 payload: typedefs.JSONObject, 1793 /, 1794 ) -> activity.Activity: 1795 period = time.clean_date(payload["period"]) 1796 details = payload["activityDetails"] 1797 ref_id = int(details["referenceId"]) 1798 instance_id = int(details["instanceId"]) 1799 mode = enums.GameMode(details["mode"]) 1800 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1801 is_private = details["isPrivate"] 1802 membership_type = enums.MembershipType(int(details["membershipType"])) 1803 1804 # Since we're using the same fields for post activity method 1805 # this check is required since post activity doesn't values values 1806 values = self._deserialize_activity_values(payload["values"]) 1807 1808 return activity.Activity( 1809 net=self._net, 1810 hash=ref_id, 1811 instance_id=instance_id, 1812 mode=mode, 1813 modes=modes, 1814 is_private=is_private, 1815 membership_type=membership_type, 1816 occurred_at=period, 1817 values=values, 1818 ) 1819 1820 def deserialize_activities( 1821 self, payload: typedefs.JSONObject 1822 ) -> iterators.FlatIterator[activity.Activity]: 1823 return iterators.FlatIterator( 1824 [ 1825 self.deserialize_activity(activity_) 1826 for activity_ in payload["activities"] 1827 ] 1828 ) 1829 1830 def deserialize_extended_weapon_values( 1831 self, payload: typedefs.JSONObject 1832 ) -> activity.ExtendedWeaponValues: 1833 1834 assists: typing.Optional[int] = None 1835 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1836 assists = raw_assists["basic"]["value"] 1837 assists_damage: typing.Optional[int] = None 1838 1839 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1840 assists_damage = raw_assists_damage["basic"]["value"] 1841 1842 return activity.ExtendedWeaponValues( 1843 reference_id=int(payload["referenceId"]), 1844 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1845 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1846 "value" 1847 ], 1848 assists=assists, 1849 assists_damage=assists_damage, 1850 precision_kills_percentage=( 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1852 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1853 "displayValue" 1854 ], 1855 ), 1856 ) 1857 1858 def _deserialize_extended_values( 1859 self, payload: typedefs.JSONObject 1860 ) -> activity.ExtendedValues: 1861 weapons: typing.Optional[ 1862 collections.Collection[activity.ExtendedWeaponValues] 1863 ] = None 1864 1865 if raw_weapons := payload.get("weapons"): 1866 weapons = [ 1867 self.deserialize_extended_weapon_values(value) for value in raw_weapons 1868 ] 1869 1870 return activity.ExtendedValues( 1871 precision_kills=payload["values"]["precisionKills"]["basic"]["value"], 1872 grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"], 1873 melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"], 1874 super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"], 1875 ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"], 1876 weapons=weapons, 1877 ) 1878 1879 def deserialize_post_activity_player( 1880 self, payload: typedefs.JSONObject, / 1881 ) -> activity.PostActivityPlayer: 1882 player = payload["player"] 1883 1884 class_hash: typedefs.NoneOr[int] = None 1885 if (class_hash := player.get("classHash")) is not None: 1886 class_hash = class_hash 1887 1888 race_hash: typedefs.NoneOr[int] = None 1889 if (race_hash := player.get("raceHash")) is not None: 1890 race_hash = race_hash 1891 1892 gender_hash: typedefs.NoneOr[int] = None 1893 if (gender_hash := player.get("genderHash")) is not None: 1894 gender_hash = gender_hash 1895 1896 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1897 if ( 1898 character_class := player.get("characterClass") 1899 ) and not typedefs.is_unknown(character_class): 1900 character_class = character_class 1901 1902 character_level: typedefs.NoneOr[int] = None 1903 if (character_level := player.get("characterLevel")) is not None: 1904 character_level = character_level 1905 1906 return activity.PostActivityPlayer( 1907 standing=int(payload["standing"]), 1908 score=int(payload["score"]["basic"]["value"]), 1909 character_id=payload["characterId"], 1910 destiny_user=self.deserialize_destiny_membership( 1911 payload["player"]["destinyUserInfo"] 1912 ), 1913 character_class=character_class, 1914 character_level=character_level, 1915 race_hash=race_hash, 1916 gender_hash=gender_hash, 1917 class_hash=class_hash, 1918 light_level=int(payload["player"]["lightLevel"]), 1919 emblem_hash=int(payload["player"]["emblemHash"]), 1920 values=self._deserialize_activity_values(payload["values"]), 1921 extended_values=self._deserialize_extended_values(payload["extended"]), 1922 ) 1923 1924 def _deserialize_post_activity_team( 1925 self, payload: typedefs.JSONObject 1926 ) -> activity.PostActivityTeam: 1927 return activity.PostActivityTeam( 1928 id=payload["teamId"], 1929 is_defeated=bool(payload["standing"]["basic"]["value"]), 1930 score=int(payload["score"]["basic"]["value"]), 1931 name=payload["teamName"], 1932 ) 1933 1934 def deserialize_post_activity( 1935 self, payload: typedefs.JSONObject 1936 ) -> activity.PostActivity: 1937 period = time.clean_date(payload["period"]) 1938 details = payload["activityDetails"] 1939 ref_id = int(details["referenceId"]) 1940 instance_id = int(details["instanceId"]) 1941 mode = enums.GameMode(details["mode"]) 1942 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1943 is_private = details["isPrivate"] 1944 membership_type = enums.MembershipType(int(details["membershipType"])) 1945 return activity.PostActivity( 1946 net=self._net, 1947 hash=ref_id, 1948 membership_type=membership_type, 1949 instance_id=instance_id, 1950 mode=mode, 1951 modes=modes, 1952 is_private=is_private, 1953 occurred_at=period, 1954 starting_phase=int(payload["startingPhaseIndex"]), 1955 players=[ 1956 self.deserialize_post_activity_player(player) 1957 for player in payload["entries"] 1958 ], 1959 teams=[ 1960 self._deserialize_post_activity_team(team) for team in payload["teams"] 1961 ], 1962 ) 1963 1964 def _deserialize_aggregated_activity_values( 1965 self, payload: typedefs.JSONObject 1966 ) -> activity.AggregatedActivityValues: 1967 # This ID is always the same for all aggregated values. 1968 activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"]) 1969 1970 return activity.AggregatedActivityValues( 1971 id=activity_id, 1972 fastest_completion_time=( 1973 int(payload["fastestCompletionMsForActivity"]["basic"]["value"]), 1974 payload["fastestCompletionMsForActivity"]["basic"]["displayValue"], 1975 ), 1976 completions=int(payload["activityCompletions"]["basic"]["value"]), 1977 kills=int(payload["activityKills"]["basic"]["value"]), 1978 deaths=int(payload["activityDeaths"]["basic"]["value"]), 1979 assists=int(payload["activityAssists"]["basic"]["value"]), 1980 seconds_played=( 1981 int(payload["activitySecondsPlayed"]["basic"]["value"]), 1982 payload["activitySecondsPlayed"]["basic"]["displayValue"], 1983 ), 1984 wins=int(payload["activityWins"]["basic"]["value"]), 1985 goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]), 1986 special_actions=int(payload["activitySpecialActions"]["basic"]["value"]), 1987 best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]), 1988 best_single_score=int( 1989 payload["activityBestSingleGameScore"]["basic"]["value"] 1990 ), 1991 goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]), 1992 special_score=int(payload["activitySpecialScore"]["basic"]["value"]), 1993 kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]), 1994 kd_ratio=float( 1995 payload["activityKillsDeathsAssists"]["basic"]["displayValue"] 1996 ), 1997 precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]), 1998 ) 1999 2000 def deserialize_aggregated_activity( 2001 self, payload: typedefs.JSONObject 2002 ) -> activity.AggregatedActivity: 2003 return activity.AggregatedActivity( 2004 hash=int(payload["activityHash"]), 2005 values=self._deserialize_aggregated_activity_values(payload["values"]), 2006 ) 2007 2008 def deserialize_aggregated_activities( 2009 self, payload: typedefs.JSONObject 2010 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2011 return iterators.FlatIterator( 2012 [ 2013 self.deserialize_aggregated_activity(activity) 2014 for activity in payload["activities"] 2015 ] 2016 ) 2017 2018 def deserialize_linked_profiles( 2019 self, payload: typedefs.JSONObject 2020 ) -> profile.LinkedProfile: 2021 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2022 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2023 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2024 2025 if raw_profile := payload.get("profiles"): 2026 for pfile in raw_profile: 2027 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2028 2029 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2030 for raw_error_pfile in raw_profiles_with_errors: 2031 if error_pfile := raw_error_pfile.get("infoCard"): 2032 error_profiles_vec.append( 2033 self.deserialize_destiny_membership(error_pfile) 2034 ) 2035 2036 return profile.LinkedProfile( 2037 net=self._net, 2038 bungie=bungie_user, 2039 profiles=profiles_vec, 2040 profiles_with_errors=error_profiles_vec, 2041 ) 2042 2043 def deserialize_clan_banners( 2044 self, payload: typedefs.JSONObject 2045 ) -> collections.Sequence[clans.ClanBanner]: 2046 banners_seq: typing.MutableSequence[clans.ClanBanner] = [] 2047 if banners := payload.get("clanBannerDecals"): 2048 for k, v in banners.items(): 2049 banner_obj = clans.ClanBanner( 2050 id=int(k), 2051 foreground=assets.Image(v["foregroundPath"]), 2052 background=assets.Image(v["backgroundPath"]), 2053 ) 2054 banners_seq.append(banner_obj) 2055 return banners_seq 2056 2057 def deserialize_public_milestone_content( 2058 self, payload: typedefs.JSONObject 2059 ) -> milestones.MilestoneContent: 2060 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2061 if raw_categories := payload.get("itemCategories"): 2062 for item in raw_categories: 2063 title = undefined.Undefined 2064 if raw_title := item.get("title"): 2065 if raw_title != typedefs.Unknown: 2066 title = raw_title 2067 if raw_hashes := item.get("itemHashes"): 2068 hashes: collections.Sequence[int] = raw_hashes 2069 2070 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2071 2072 about = undefined.Undefined 2073 if (raw_about := payload["about"]) != typedefs.Unknown: 2074 about = raw_about 2075 2076 status = undefined.Undefined 2077 if (raw_status := payload["status"]) != typedefs.Unknown: 2078 status = raw_status 2079 2080 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2081 if raw_tips := payload.get("tips"): 2082 for raw_tip in raw_tips: 2083 if raw_tip == typedefs.Unknown: 2084 raw_tip = undefined.Undefined 2085 tips.append(raw_tip) 2086 2087 return milestones.MilestoneContent( 2088 about=about, status=status, tips=tips, items=items_categoris 2089 ) 2090 2091 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2092 name = undefined.Undefined 2093 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2094 name = raw_name 2095 2096 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2097 2098 if raw_bungie_user := payload.get("bungieNetUser"): 2099 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2100 2101 return friends.Friend( 2102 net=self._net, 2103 id=int(payload["lastSeenAsMembershipId"]), 2104 name=name, 2105 code=payload.get("bungieGlobalDisplayNameCode"), 2106 relationship=enums.Relationship(payload["relationship"]), 2107 user=bungie_user, 2108 online_status=enums.Presence(payload["onlineStatus"]), 2109 online_title=payload["onlineTitle"], 2110 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2111 ) 2112 2113 def deserialize_friends( 2114 self, payload: typedefs.JSONObject 2115 ) -> collections.Sequence[friends.Friend]: 2116 mut_seq: typing.MutableSequence[friends.Friend] = [] 2117 if raw_friends := payload.get("friends"): 2118 for friend in raw_friends: 2119 mut_seq.append(self.deserialize_friend(friend)) 2120 return mut_seq 2121 2122 def deserialize_friend_requests( 2123 self, payload: typedefs.JSONObject 2124 ) -> friends.FriendRequestView: 2125 incoming: typing.MutableSequence[friends.Friend] = [] 2126 outgoing: typing.MutableSequence[friends.Friend] = [] 2127 2128 if raw_incoming_requests := payload.get("incomingRequests"): 2129 for incoming_request in raw_incoming_requests: 2130 incoming.append(self.deserialize_friend(incoming_request)) 2131 2132 if raw_outgoing_requests := payload.get("outgoingRequests"): 2133 for outgoing_request in raw_outgoing_requests: 2134 outgoing.append(self.deserialize_friend(outgoing_request)) 2135 2136 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing) 2137 2138 def _set_fireteam_fields( 2139 self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None 2140 ) -> fireteams.Fireteam: 2141 activity_type = fireteams.FireteamActivity(payload["activityType"]) 2142 return fireteams.Fireteam( 2143 id=int(payload["fireteamId"]), 2144 group_id=int(payload["groupId"]), 2145 platform=fireteams.FireteamPlatform(payload["platform"]), 2146 is_immediate=payload["isImmediate"], 2147 activity_type=activity_type, 2148 owner_id=int(payload["ownerMembershipId"]), 2149 player_slot_count=payload["playerSlotCount"], 2150 available_player_slots=payload["availablePlayerSlotCount"], 2151 available_alternate_slots=payload["availableAlternateSlotCount"], 2152 title=payload["title"], 2153 date_created=time.clean_date(payload["dateCreated"]), 2154 is_public=payload["isPublic"], 2155 locale=fireteams.FireteamLanguage(payload["locale"]), 2156 is_valid=payload["isValid"], 2157 last_modified=time.clean_date(payload["datePlayerModified"]), 2158 total_results=total_results or 0, 2159 ) 2160 2161 def deserialize_fireteams( 2162 self, payload: typedefs.JSONObject 2163 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2164 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2165 2166 result: list[typedefs.JSONObject] 2167 if not (result := payload["results"]): 2168 return None 2169 for elem in result: 2170 fireteams_.append( 2171 self._set_fireteam_fields( 2172 elem, total_results=int(payload["totalResults"]) 2173 ) 2174 ) 2175 return fireteams_ 2176 2177 def deserialize_fireteam_destiny_users( 2178 self, payload: typedefs.JSONObject 2179 ) -> fireteams.FireteamUser: 2180 destiny_obj = self.deserialize_destiny_membership(payload) 2181 # We could helpers.just return a DestinyMembership object but this is 2182 # missing the fireteam display name and id fields. 2183 return fireteams.FireteamUser( 2184 net=self._net, 2185 id=destiny_obj.id, 2186 code=destiny_obj.code, 2187 icon=destiny_obj.icon, 2188 types=destiny_obj.types, 2189 type=destiny_obj.type, 2190 is_public=destiny_obj.is_public, 2191 crossave_override=destiny_obj.crossave_override, 2192 name=destiny_obj.name, 2193 last_seen_name=destiny_obj.last_seen_name, 2194 fireteam_display_name=payload["FireteamDisplayName"], 2195 fireteam_membership_id=enums.MembershipType( 2196 payload["FireteamMembershipType"] 2197 ), 2198 ) 2199 2200 def deserialize_fireteam_members( 2201 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2202 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2203 members_: list[fireteams.FireteamMember] = [] 2204 if members := payload.get("Members" if not alternatives else "Alternates"): 2205 for member in members: 2206 bungie_fields = self.deserialize_partial_bungie_user(member) 2207 members_fields = fireteams.FireteamMember( 2208 destiny_user=self.deserialize_fireteam_destiny_users(member), 2209 has_microphone=member["hasMicrophone"], 2210 character_id=int(member["characterId"]), 2211 date_joined=time.clean_date(member["dateJoined"]), 2212 last_platform_invite_date=time.clean_date( 2213 member["lastPlatformInviteAttemptDate"] 2214 ), 2215 last_platform_invite_result=int( 2216 member["lastPlatformInviteAttemptResult"] 2217 ), 2218 net=self._net, 2219 name=bungie_fields.name, 2220 id=bungie_fields.id, 2221 icon=bungie_fields.icon, 2222 is_public=bungie_fields.is_public, 2223 crossave_override=bungie_fields.crossave_override, 2224 types=bungie_fields.types, 2225 type=bungie_fields.type, 2226 ) 2227 members_.append(members_fields) 2228 else: 2229 return None 2230 return members_ 2231 2232 def deserialize_available_fireteams( 2233 self, 2234 data: typedefs.JSONObject, 2235 *, 2236 no_results: bool = False, 2237 ) -> typing.Union[ 2238 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2239 ]: 2240 fireteams_: list[fireteams.AvailableFireteam] = [] 2241 2242 # This needs to be used outside the results 2243 # JSON key. 2244 if no_results is True: 2245 payload = data 2246 2247 if result := payload.get("results"): 2248 2249 for fireteam in result: 2250 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2251 fireteams_fields = fireteams.AvailableFireteam( 2252 id=found_fireteams.id, 2253 group_id=found_fireteams.group_id, 2254 platform=found_fireteams.platform, 2255 activity_type=found_fireteams.activity_type, 2256 is_immediate=found_fireteams.is_immediate, 2257 is_public=found_fireteams.is_public, 2258 is_valid=found_fireteams.is_valid, 2259 owner_id=found_fireteams.owner_id, 2260 player_slot_count=found_fireteams.player_slot_count, 2261 available_player_slots=found_fireteams.available_player_slots, 2262 available_alternate_slots=found_fireteams.available_alternate_slots, 2263 title=found_fireteams.title, 2264 date_created=found_fireteams.date_created, 2265 locale=found_fireteams.locale, 2266 last_modified=found_fireteams.last_modified, 2267 total_results=found_fireteams.total_results, 2268 members=self.deserialize_fireteam_members(payload), 2269 alternatives=self.deserialize_fireteam_members( 2270 payload, alternatives=True 2271 ), 2272 ) 2273 fireteams_.append(fireteams_fields) 2274 if no_results: 2275 return fireteams_fields 2276 return fireteams_ 2277 2278 def deserialize_fireteam_party( 2279 self, payload: typedefs.JSONObject 2280 ) -> fireteams.FireteamParty: 2281 last_destination_hash: typing.Optional[int] = None 2282 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2283 last_destination_hash = int(raw_dest_hash) 2284 2285 return fireteams.FireteamParty( 2286 members=[ 2287 self._deserialize_fireteam_party_member(member) 2288 for member in payload["partyMembers"] 2289 ], 2290 activity=self._deserialize_fireteam_party_current_activity( 2291 payload["currentActivity"] 2292 ), 2293 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2294 last_destination_hash=last_destination_hash, 2295 tracking=payload["tracking"], 2296 ) 2297 2298 def _deserialize_fireteam_party_member( 2299 self, payload: typedefs.JSONObject 2300 ) -> fireteams.FireteamPartyMember: 2301 2302 status = fireteams.FireteamPartyMemberState(payload["status"]) 2303 displayname: undefined.UndefinedOr[str] = undefined.Undefined 2304 if raw_name := payload.get("displayName"): 2305 displayname = raw_name 2306 2307 return fireteams.FireteamPartyMember( 2308 membership_id=int(payload["membershipId"]), 2309 emblem_hash=int(payload["emblemHash"]), 2310 status=status, 2311 display_name=displayname, 2312 ) 2313 2314 def _deserialize_fireteam_party_current_activity( 2315 self, payload: typedefs.JSONObject 2316 ) -> fireteams.FireteamPartyCurrentActivity: 2317 start_date: typing.Optional[datetime.datetime] = None 2318 if raw_start_date := payload.get("startTime"): 2319 start_date = time.clean_date(raw_start_date) 2320 2321 end_date: typing.Optional[datetime.datetime] = None 2322 if raw_end_date := payload.get("endTime"): 2323 end_date = time.clean_date(raw_end_date) 2324 return fireteams.FireteamPartyCurrentActivity( 2325 start_time=start_date, 2326 end_time=end_date, 2327 score=float(payload["score"]), 2328 highest_opposing_score=float(payload["highestOpposingFactionScore"]), 2329 opponenst_count=int(payload["numberOfOpponents"]), 2330 player_count=int(payload["numberOfPlayers"]), 2331 ) 2332 2333 def _deserialize_fireteam_party_settings( 2334 self, payload: typedefs.JSONObject 2335 ) -> fireteams.FireteamPartySettings: 2336 closed_reasons = enums.ClosedReasons(payload["closedReasons"]) 2337 return fireteams.FireteamPartySettings( 2338 open_slots=int(payload["openSlots"]), 2339 privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])), 2340 closed_reasons=closed_reasons, 2341 ) 2342 2343 def deserialize_seasonal_artifact( 2344 self, payload: typedefs.JSONObject 2345 ) -> season.Artifact: 2346 if raw_artifact := payload.get("seasonalArtifact"): 2347 if points := raw_artifact.get("pointProgression"): 2348 points_prog = progressions.Progression( 2349 hash=points["progressionHash"], 2350 level=points["level"], 2351 cap=points["levelCap"], 2352 daily_limit=points["dailyLimit"], 2353 weekly_limit=points["weeklyLimit"], 2354 current_progress=points["currentProgress"], 2355 daily_progress=points["dailyProgress"], 2356 needed=points["progressToNextLevel"], 2357 next_level=points["nextLevelAt"], 2358 ) 2359 2360 if bonus := raw_artifact.get("powerBonusProgression"): 2361 power_bonus_prog = progressions.Progression( 2362 hash=bonus["progressionHash"], 2363 level=bonus["level"], 2364 cap=bonus["levelCap"], 2365 daily_limit=bonus["dailyLimit"], 2366 weekly_limit=bonus["weeklyLimit"], 2367 current_progress=bonus["currentProgress"], 2368 daily_progress=bonus["dailyProgress"], 2369 needed=bonus["progressToNextLevel"], 2370 next_level=bonus["nextLevelAt"], 2371 ) 2372 artifact = season.Artifact( 2373 net=self._net, 2374 hash=raw_artifact["artifactHash"], 2375 power_bonus=raw_artifact["powerBonus"], 2376 acquired_points=raw_artifact["pointsAcquired"], 2377 bonus=power_bonus_prog, 2378 points=points_prog, 2379 ) 2380 return artifact 2381 2382 def deserialize_profile_progression( 2383 self, payload: typedefs.JSONObject 2384 ) -> profile.ProfileProgression: 2385 return profile.ProfileProgression( 2386 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2387 checklist={ 2388 int(check_id): checklists 2389 for check_id, checklists in payload["data"]["checklists"].items() 2390 }, 2391 ) 2392 2393 def deserialize_instanced_item( 2394 self, payload: typedefs.JSONObject 2395 ) -> items.ItemInstance: 2396 damage_type_hash: typing.Optional[int] = None 2397 if raw_damagetype_hash := payload.get("damageTypeHash"): 2398 damage_type_hash = int(raw_damagetype_hash) 2399 2400 required_hashes: typing.Optional[collections.Collection[int]] = None 2401 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2402 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2403 2404 breaker_type: typing.Optional[items.ItemBreakerType] = None 2405 if raw_break_type := payload.get("breakerType"): 2406 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2407 2408 breaker_type_hash: typing.Optional[int] = None 2409 if raw_break_type_hash := payload.get("breakerTypeHash"): 2410 breaker_type_hash = int(raw_break_type_hash) 2411 2412 energy: typing.Optional[items.ItemEnergy] = None 2413 if raw_energy := payload.get("energy"): 2414 energy = self.deserialize_item_energy(raw_energy) 2415 2416 primary_stats = None 2417 if raw_primary_stats := payload.get("primaryStat"): 2418 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2419 2420 return items.ItemInstance( 2421 damage_type=enums.DamageType(int(payload["damageType"])), 2422 damage_type_hash=damage_type_hash, 2423 primary_stat=primary_stats, 2424 item_level=int(payload["itemLevel"]), 2425 quality=int(payload["quality"]), 2426 is_equipped=payload["isEquipped"], 2427 can_equip=payload["canEquip"], 2428 equip_required_level=int(payload["equipRequiredLevel"]), 2429 required_equip_unlock_hashes=required_hashes, 2430 cant_equip_reason=int(payload["cannotEquipReason"]), 2431 breaker_type=breaker_type, 2432 breaker_type_hash=breaker_type_hash, 2433 energy=energy, 2434 ) 2435 2436 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2437 energy_hash: typing.Optional[int] = None 2438 if raw_energy_hash := payload.get("energyTypeHash"): 2439 energy_hash = int(raw_energy_hash) 2440 2441 return items.ItemEnergy( 2442 hash=energy_hash, 2443 type=items.ItemEnergyType(int(payload["energyType"])), 2444 capacity=int(payload["energyCapacity"]), 2445 used_energy=int(payload["energyUsed"]), 2446 unused_energy=int(payload["energyUnused"]), 2447 ) 2448 2449 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2450 perk_hash: typing.Optional[int] = None 2451 if raw_perk_hash := payload.get("perkHash"): 2452 perk_hash = int(raw_perk_hash) 2453 2454 return items.ItemPerk( 2455 hash=perk_hash, 2456 icon=assets.Image(payload["iconPath"]), 2457 is_active=payload["isActive"], 2458 is_visible=payload["visible"], 2459 ) 2460 2461 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2462 plug_hash: typing.Optional[int] = None 2463 if raw_plug_hash := payload.get("plugHash"): 2464 plug_hash = int(raw_plug_hash) 2465 2466 enable_fail_indexes: typing.Optional[list[int]] = None 2467 if raw_indexes := payload.get("enableFailIndexes"): 2468 enable_fail_indexes = [int(index) for index in raw_indexes] 2469 2470 return items.ItemSocket( 2471 plug_hash=plug_hash, 2472 is_enabled=payload["isEnabled"], 2473 enable_fail_indexes=enable_fail_indexes, 2474 is_visible=payload.get("visible"), 2475 ) 2476 2477 def deserialize_item_stats_view( 2478 self, payload: typedefs.JSONObject 2479 ) -> items.ItemStatsView: 2480 return items.ItemStatsView( 2481 stat_hash=payload.get("statHash"), value=payload.get("value") 2482 ) 2483 2484 def deserialize_plug_item_state( 2485 self, payload: typedefs.JSONObject 2486 ) -> items.PlugItemState: 2487 item_hash: typing.Optional[int] = None 2488 if raw_item_hash := payload.get("plugItemHash"): 2489 item_hash = int(raw_item_hash) 2490 2491 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2492 if raw_fail_indexes := payload.get("insertFailIndexes"): 2493 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2494 2495 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2496 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2497 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2498 2499 return items.PlugItemState( 2500 item_hash=item_hash, 2501 insert_fail_indexes=insert_fail_indexes, 2502 enable_fail_indexes=enable_fail_indexes, 2503 is_enabled=payload["enabled"], 2504 can_insert=payload["canInsert"], 2505 )
The base deserialization factory class for all aiobungie objects.
Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
into a aiobungie.crates Python classes.
73 def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser: 74 return user.BungieUser( 75 id=int(data["membershipId"]), 76 created_at=time.clean_date(data["firstAccess"]), 77 name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined), 78 is_deleted=data["isDeleted"], 79 about=data["about"], 80 updated_at=time.clean_date(data["lastUpdate"]), 81 psn_name=data.get("psnDisplayName", None), 82 stadia_name=data.get("stadiaDisplayName", None), 83 steam_name=data.get("steamDisplayName", None), 84 twitch_name=data.get("twitchDisplayName", None), 85 blizzard_name=data.get("blizzardDisplayName", None), 86 status=data["statusText"], 87 locale=data["locale"], 88 picture=assets.Image(path=str(data["profilePicturePath"])), 89 code=data.get("cachedBungieGlobalDisplayNameCode", None), 90 unique_name=data.get("uniqueName", None), 91 theme_id=int(data["profileTheme"]), 92 show_activity=bool(data["showActivity"]), 93 theme_name=data["profileThemeName"], 94 display_title=data["userTitleDisplay"], 95 )
Deserialize a raw JSON Bungie.net user only payload into a user object.
This only returns the Bungie.net user and not the Destiny memberships.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.BungieUser: A Bungie user.
97 def deserialize_partial_bungie_user( 98 self, payload: typedefs.JSONObject 99 ) -> user.PartialBungieUser: 100 return user.PartialBungieUser( 101 net=self._net, 102 types=[ 103 enums.MembershipType(type_) 104 for type_ in payload.get("applicableMembershipTypes", []) 105 ], 106 name=payload.get("displayName", undefined.Undefined), 107 id=int(payload["membershipId"]), 108 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 109 is_public=payload["isPublic"], 110 icon=assets.Image(payload.get("iconPath", "")), 111 type=enums.MembershipType(payload["membershipType"]), 112 )
Deserialize a raw JSON of a partial bungieNetUserInfo.
A partial user is a bungie.net user payload with missing information from
the main BungieUser object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PartialBungieUser: A partial bungie user.
114 def deserialize_destiny_membership( 115 self, payload: typedefs.JSONObject 116 ) -> user.DestinyMembership: 117 name: undefined.UndefinedOr[str] = undefined.Undefined 118 if ( 119 raw_name := payload.get("bungieGlobalDisplayName", "") 120 ) and not typedefs.is_unknown(raw_name): 121 name = raw_name 122 123 return user.DestinyMembership( 124 net=self._net, 125 id=int(payload["membershipId"]), 126 name=name, 127 code=payload.get("bungieGlobalDisplayNameCode", None), 128 last_seen_name=payload.get("LastSeenDisplayName") 129 or payload.get("displayName") 130 or "", 131 type=enums.MembershipType(payload["membershipType"]), 132 is_public=payload["isPublic"], 133 crossave_override=enums.MembershipType(payload["crossSaveOverride"]), 134 icon=assets.Image(payload.get("iconPath", "")), 135 types=[ 136 enums.MembershipType(type_) 137 for type_ in payload["applicableMembershipTypes"] 138 if "applicableMembershipTypes" in payload 139 ], 140 )
Deserialize a raw JSON of destinyUserInfo destiny membership information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
142 def deserialize_destiny_memberships( 143 self, data: typedefs.JSONArray 144 ) -> collections.Sequence[user.DestinyMembership]: 145 return [self.deserialize_destiny_membership(membership) for membership in data]
Deserialize a raw JSON payload/array of destinyUserInfo.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
147 def deserialize_user(self, data: typedefs.JSONObject) -> user.User: 148 149 primary_membership_id: typing.Optional[int] = None 150 if raw_primary_id := data.get("primaryMembershipId"): 151 primary_membership_id = int(raw_primary_id) 152 153 return user.User( 154 bungie=self.deserialize_bungie_user(data["bungieNetUser"]), 155 destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]), 156 primary_membership_id=primary_membership_id, 157 )
Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON data/payload.
Returns
aiobungie.crates.User: A user object.
159 def deserialize_searched_user( 160 self, payload: typedefs.JSONObject 161 ) -> user.SearchableDestinyUser: 162 name: undefined.UndefinedOr[str] = undefined.Undefined 163 if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown( 164 raw_name 165 ): 166 name = raw_name 167 168 code: typing.Optional[int] = None 169 if raw_code := payload.get("bungieGlobalDisplayNameCode"): 170 code = int(raw_code) 171 172 bungie_id: typing.Optional[int] = None 173 if raw_bungie_id := payload.get("bungieNetMembershipId"): 174 bungie_id = int(raw_bungie_id) 175 176 return user.SearchableDestinyUser( 177 name=name, 178 code=code, 179 bungie_id=bungie_id, 180 memberships=self.deserialize_destiny_memberships( 181 payload["destinyMemberships"] 182 ), 183 )
Deserialize the results of user search details.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.SearchableDestinyUser: The searched for Destiny 2 membership.
185 def deserialize_user_credentials( 186 self, payload: typedefs.JSONArray 187 ) -> collections.Sequence[user.UserCredentials]: 188 return [ 189 user.UserCredentials( 190 type=enums.CredentialType(int(creds["credentialType"])), 191 display_name=creds["credentialDisplayName"], 192 is_public=creds["isPublic"], 193 self_as_string=creds.get("credentialAsString", undefined.Undefined), 194 ) 195 for creds in payload 196 ]
Deserialize a JSON array of Bungie user credentials.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.UserCredentials]: A sequence of user's credentials.
198 @staticmethod 199 def set_themese_attrs( 200 payload: typedefs.JSONArray, / 201 ) -> typing.Collection[user.UserThemes]: 202 return [ 203 user.UserThemes( 204 id=int(entry["userThemeId"]), 205 name=entry["userThemeName"] 206 if "userThemeName" in entry 207 else undefined.Undefined, 208 description=entry["userThemeDescription"] 209 if "userThemeDescription" in entry 210 else undefined.Undefined, 211 ) 212 for entry in payload 213 ]
215 def deserialize_user_themes( 216 self, payload: typedefs.JSONArray 217 ) -> collections.Sequence[user.UserThemes]: 218 return list(self.set_themese_attrs(payload))
Deserialize a raw JSON array of Bungie user themes.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
220 def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan: 221 222 # This is kinda redundant 223 data = payload 224 225 # This is always outside the details. 226 current_user_map: typing.Optional[ 227 collections.Mapping[str, clans.ClanMember] 228 ] = None 229 if raw_current_user_map := payload.get("currentUserMemberMap"): 230 current_user_map = { 231 membership_type: self.deserialize_clan_member(membership) 232 for membership_type, membership in raw_current_user_map.items() 233 } 234 235 try: 236 data = payload["detail"] 237 except KeyError: 238 pass 239 240 id = data["groupId"] 241 name = data["name"] 242 created_at = data["creationDate"] 243 member_count = data["memberCount"] 244 about = data["about"] 245 motto = data["motto"] 246 is_public = data["isPublic"] 247 banner = assets.Image(str(data["bannerPath"])) 248 avatar = assets.Image(str(data["avatarPath"])) 249 tags = data["tags"] 250 type = data["groupType"] 251 252 features = data["features"] 253 features_obj = clans.ClanFeatures( 254 max_members=features["maximumMembers"], 255 max_membership_types=features["maximumMembershipsOfGroupType"], 256 capabilities=features["capabilities"], 257 membership_types=features["membershipTypes"], 258 invite_permissions=features["invitePermissionOverride"], 259 update_banner_permissions=features["updateBannerPermissionOverride"], 260 update_culture_permissions=features["updateCulturePermissionOverride"], 261 join_level=features["joinLevel"], 262 ) 263 264 information: typedefs.JSONObject = data["clanInfo"] 265 progression: collections.Mapping[int, progressions.Progression] = { 266 int(prog_hash): self.deserialize_progressions(prog) 267 for prog_hash, prog in information["d2ClanProgressions"].items() 268 } 269 270 founder: typedefs.NoneOr[clans.ClanMember] = None 271 if raw_founder := payload.get("founder"): 272 founder = self.deserialize_clan_member(raw_founder) 273 274 return clans.Clan( 275 net=self._net, 276 id=int(id), 277 name=name, 278 type=enums.GroupType(type), 279 created_at=time.clean_date(created_at), 280 member_count=member_count, 281 motto=motto, 282 about=about, 283 is_public=is_public, 284 banner=banner, 285 avatar=avatar, 286 tags=tags, 287 features=features_obj, 288 owner=founder, 289 progressions=progression, 290 call_sign=information["clanCallsign"], 291 banner_data=information["clanBannerData"], 292 chat_security=data["chatSecurity"], 293 conversation_id=int(data["conversationId"]), 294 allow_chat=data["allowChat"], 295 theme=data["theme"], 296 current_user_membership=current_user_map, 297 )
Deserialize a raw JSON payload of Bungie clan information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Clan: A clan owner.
299 def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember: 300 destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"]) 301 return clans.ClanMember( 302 net=self._net, 303 last_seen_name=destiny_user.last_seen_name, 304 id=destiny_user.id, 305 name=destiny_user.name, 306 icon=destiny_user.icon, 307 last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])), 308 group_id=int(data["groupId"]), 309 joined_at=time.clean_date(data["joinDate"]), 310 types=destiny_user.types, 311 is_public=destiny_user.is_public, 312 type=destiny_user.type, 313 code=destiny_user.code, 314 is_online=data["isOnline"], 315 crossave_override=destiny_user.crossave_override, 316 bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"]) 317 if "bungieNetUserInfo" in data 318 else None, 319 member_type=enums.ClanMemberType(int(data["memberType"])), 320 )
Deserialize a JSON payload of a clan member information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ClanMember: A clan member.
322 def deserialize_clan_members( 323 self, data: typedefs.JSONObject, / 324 ) -> iterators.FlatIterator[clans.ClanMember]: 325 return iterators.FlatIterator( 326 [self.deserialize_clan_member(member) for member in data["results"]] 327 )
Deserialize a JSON payload of a clan members information.
Parameters
- data (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]: An iterator of clan members of the deserialized payload.
329 def deserialize_group_member( 330 self, payload: typedefs.JSONObject 331 ) -> clans.GroupMember: 332 member = payload["member"] 333 return clans.GroupMember( 334 net=self._net, 335 join_date=time.clean_date(member["joinDate"]), 336 group_id=int(member["groupId"]), 337 member_type=enums.ClanMemberType(member["memberType"]), 338 is_online=member["isOnline"], 339 last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])), 340 inactive_memberships=payload.get("areAllMembershipsInactive", None), 341 member=self.deserialize_destiny_membership(member["destinyUserInfo"]), 342 group=self.deserialize_clan(payload["group"]), 343 )
Deserialize a JSON payload of group information for a member.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.typedefs.NoneOr[aiobungie.crates.GroupMember]: A group member. This can returnNoneif nothing was found.
361 def deserialize_clan_conversations( 362 self, payload: typedefs.JSONArray 363 ) -> collections.Sequence[clans.ClanConversation]: 364 return [self._deserialize_clan_conversation(conv) for conv in payload]
Deserialize a JSON array of a clan conversations information.
Parameters
- payload (
aiobungie.typedefs.JSONArray): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.ClanConversation]: A sequence of clan conversations of the deserialized payload.
366 def deserialize_app_owner( 367 self, payload: typedefs.JSONObject 368 ) -> application.ApplicationOwner: 369 return application.ApplicationOwner( 370 net=self._net, 371 name=payload.get("bungieGlobalDisplayName", undefined.Undefined), 372 id=int(payload["membershipId"]), 373 type=enums.MembershipType(payload["membershipType"]), 374 icon=assets.Image(str(payload["iconPath"])), 375 is_public=payload["isPublic"], 376 code=payload.get("bungieGlobalDisplayNameCode", None), 377 )
Deserialize a JSON payload of Bungie Developer portal application owner information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.ApplicationOwner: An application owner.
379 def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application: 380 return application.Application( 381 id=int(payload["applicationId"]), 382 name=payload["name"], 383 link=payload["link"], 384 status=payload["status"], 385 redirect_url=payload.get("redirectUrl", None), 386 created_at=time.clean_date(str(payload["creationDate"])), 387 published_at=time.clean_date(str(payload["firstPublished"])), 388 owner=self.deserialize_app_owner(payload["team"][0]["user"]), # type: ignore 389 scope=payload.get("scope", undefined.Undefined), 390 )
Deserialize a JSON payload of Bungie Developer portal application information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.application.Application: An application.
413 def deserialize_profile( 414 self, payload: typedefs.JSONObject, / 415 ) -> typing.Optional[profile.Profile]: 416 if (raw_profile := payload.get("data")) is None: 417 return None 418 419 payload = raw_profile 420 id = int(payload["userInfo"]["membershipId"]) 421 name = payload["userInfo"]["displayName"] 422 is_public = payload["userInfo"]["isPublic"] 423 type = enums.MembershipType(payload["userInfo"]["membershipType"]) 424 last_played = time.clean_date(str(payload["dateLastPlayed"])) 425 character_ids = [int(cid) for cid in payload["characterIds"]] 426 power_cap = payload["currentSeasonRewardPowerCap"] 427 428 return profile.Profile( 429 id=int(id), 430 name=name, 431 is_public=is_public, 432 type=type, 433 last_played=last_played, 434 character_ids=character_ids, 435 power_cap=power_cap, 436 net=self._net, 437 )
Deserialize a JSON payload of Bungie.net profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[aiobungie.crates.Profile]: A profile.
439 def deserialize_profile_item( 440 self, payload: typedefs.JSONObject 441 ) -> profile.ProfileItemImpl: 442 443 instance_id: typing.Optional[int] = None 444 if raw_instance_id := payload.get("itemInstanceId"): 445 instance_id = int(raw_instance_id) 446 447 version_number: typing.Optional[int] = None 448 if raw_version := payload.get("versionNumber"): 449 version_number = int(raw_version) 450 451 transfer_status = enums.TransferStatus(payload["transferStatus"]) 452 453 return profile.ProfileItemImpl( 454 net=self._net, 455 hash=payload["itemHash"], 456 quantity=payload["quantity"], 457 bind_status=enums.ItemBindStatus(payload["bindStatus"]), 458 location=enums.ItemLocation(payload["location"]), 459 bucket=payload["bucketHash"], 460 transfer_status=transfer_status, 461 lockable=payload["lockable"], 462 state=enums.ItemState(payload["state"]), 463 dismantel_permissions=payload["dismantlePermission"], 464 is_wrapper=payload["isWrapper"], 465 instance_id=instance_id, 466 version_number=version_number, 467 ornament_id=payload.get("overrideStyleItemHash"), 468 )
Deserialize a JSON payload of a singular profile component item.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ProfileItemImpl: Implementation of a Destiny 2 profile component item.
470 def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective: 471 return records.Objective( 472 net=self._net, 473 hash=payload["objectiveHash"], 474 visible=payload["visible"], 475 complete=payload["complete"], 476 completion_value=payload["completionValue"], 477 progress=payload.get("progress"), 478 destination_hash=payload.get("destinationHash"), 479 activity_hash=payload.get("activityHash"), 480 )
Deserialize a JSON payload of an objective found in a record profile component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.records.Objective: A record objective object.
482 def deserialize_records( 483 self, 484 payload: typedefs.JSONObject, 485 scores: typing.Optional[records.RecordScores] = None, 486 **nodes: int, 487 ) -> records.Record: 488 objectives: typing.Optional[list[records.Objective]] = None 489 interval_objectives: typing.Optional[list[records.Objective]] = None 490 record_state: typedefs.IntAnd[records.RecordState] 491 492 record_state = records.RecordState(payload["state"]) 493 494 if raw_objs := payload.get("objectives"): 495 objectives = [self.deserialize_objectives(obj) for obj in raw_objs] 496 497 if raw_interval_objs := payload.get("intervalObjectives"): 498 interval_objectives = [ 499 self.deserialize_objectives(obj) for obj in raw_interval_objs 500 ] 501 502 return records.Record( 503 scores=scores, 504 categories_node_hash=nodes.get("categories_hash", undefined.Undefined), 505 seals_node_hash=nodes.get("seals_hash", undefined.Undefined), 506 state=record_state, 507 objectives=objectives, 508 interval_objectives=interval_objectives, 509 redeemed_count=payload.get("intervalsRedeemedCount", 0), 510 completion_times=payload.get("completedCount", None), 511 reward_visibility=payload.get("rewardVisibilty", None), 512 )
Deserialize a JSON object of a profile record component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload - scores (
typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature ofaiobungie.crates.CharacterRecordwith the record object. As it will always beNonein that object. - **nodes (
int): An int kwargs use to grab the node hashes while deserializing components.
Returns
aiobungie.records.Record: A standard implementation of a profile record component.
514 def deserialize_character_records( 515 self, 516 payload: typedefs.JSONObject, 517 scores: typing.Optional[records.RecordScores] = None, 518 record_hashes: typing.Optional[list[int]] = None, 519 ) -> records.CharacterRecord: 520 521 record = self.deserialize_records(payload, scores) 522 return records.CharacterRecord( 523 scores=scores, 524 categories_node_hash=record.categories_node_hash, 525 seals_node_hash=record.seals_node_hash, 526 state=record.state, 527 objectives=record.objectives, 528 interval_objectives=record.interval_objectives, 529 redeemed_count=payload.get("intervalsRedeemedCount", 0), 530 completion_times=payload.get("completedCount"), 531 reward_visibility=payload.get("rewardVisibilty"), 532 record_hashes=record_hashes or [], 533 )
Deserialize a JSON object of a profile character record component.
This almost does the same this as deserialize_records but
has more fields which can only be found in a character record.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
535 def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye: 536 return character.Dye( 537 channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"] 538 )
Deserialize a JSON payload of a character's dye information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.Dye: Information about a character dye object.
540 def deserialize_character_customization( 541 self, payload: typedefs.JSONObject 542 ) -> character.CustomizationOptions: 543 return character.CustomizationOptions( 544 personality=payload["personality"], 545 face=payload["face"], 546 skin_color=payload["skinColor"], 547 lip_color=payload["lipColor"], 548 eye_color=payload["eyeColor"], 549 hair_colors=payload.get("hairColors", []), 550 feature_colors=payload.get("featureColors", []), 551 decal_color=payload["decalColor"], 552 wear_helmet=payload["wearHelmet"], 553 hair_index=payload["hairIndex"], 554 feature_index=payload["featureIndex"], 555 decal_index=payload["decalIndex"], 556 )
Deserialize a JSON payload of a character customization information found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
558 def deserialize_character_minimal_equipments( 559 self, payload: typedefs.JSONObject 560 ) -> character.MinimalEquipments: 561 dyes = None 562 if raw_dyes := payload.get("dyes"): 563 if raw_dyes: 564 dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes] 565 return character.MinimalEquipments( 566 net=self._net, item_hash=payload["itemHash"], dyes=dyes 567 )
Deserialize a singular JSON peer view of equipment found in character render data profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
569 def deserialize_character_render_data( 570 self, payload: typedefs.JSONObject, / 571 ) -> character.RenderedData: 572 return character.RenderedData( 573 net=self._net, 574 customization=self.deserialize_character_customization( 575 payload["customization"] 576 ), 577 custom_dyes=[ 578 self.deserialize_character_dye(dye) 579 for dye in payload["customDyes"] 580 if dye 581 ], 582 equipment=[ 583 self.deserialize_character_minimal_equipments(equipment) 584 for equipment in payload["peerView"]["equipment"] 585 ], 586 )
Deserialize a JSON payload of a profile character render data component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.RenderedData: A character rendered data profile component.
588 def deserialize_available_activity( 589 self, payload: typedefs.JSONObject 590 ) -> activity.AvailableActivity: 591 return activity.AvailableActivity( 592 hash=payload["activityHash"], 593 is_new=payload["isNew"], 594 is_completed=payload["isCompleted"], 595 is_visible=payload["isVisible"], 596 display_level=payload.get("displayLevel"), 597 recommended_light=payload.get("recommendedLight"), 598 difficulty=activity.Difficulty(payload["difficultyTier"]), 599 can_join=payload["canJoin"], 600 can_lead=payload["canLead"], 601 )
Deserialize a JSON payload of an available activities.
This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AvailableActivity: An available activity object.
603 def deserialize_character_activity( 604 self, payload: typedefs.JSONObject 605 ) -> activity.CharacterActivity: 606 current_mode: typing.Optional[enums.GameMode] = None 607 if raw_current_mode := payload.get("currentActivityModeType"): 608 current_mode = enums.GameMode(raw_current_mode) 609 610 current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None 611 if raw_current_modes := payload.get("currentActivityModeTypes"): 612 current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes] 613 614 return activity.CharacterActivity( 615 date_started=time.clean_date(payload["dateActivityStarted"]), 616 current_hash=payload["currentActivityHash"], 617 current_mode_hash=payload["currentActivityModeHash"], 618 current_mode=current_mode, 619 current_mode_hashes=payload.get("currentActivityModeHashes"), 620 current_mode_types=current_mode_types, 621 current_playlist_hash=payload.get("currentPlaylistActivityHash"), 622 last_story_hash=payload["lastCompletedStoryHash"], 623 available_activities=[ 624 self.deserialize_available_activity(activity_) 625 for activity_ in payload["availableActivities"] 626 ], 627 )
Deserialize a JSON payload of character activity profile component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterActivity: A character activities component object.
629 def deserialize_profile_items( 630 self, payload: typedefs.JSONObject, / 631 ) -> list[profile.ProfileItemImpl]: 632 return [self.deserialize_profile_item(item) for item in payload["items"]]
Deserialize a JSON payload of profile items component information.
This may deserialize profileInventories or profileCurrencies or any
other alternatives.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.ProfileItemImpl]]: A profile component object that contains items of the deserialized payload.
675 def deserialize_progressions( 676 self, payload: typedefs.JSONObject 677 ) -> progressions.Progression: 678 return progressions.Progression( 679 hash=int(payload["progressionHash"]), 680 level=int(payload["level"]), 681 cap=int(payload["levelCap"]), 682 daily_limit=int(payload["dailyLimit"]), 683 weekly_limit=int(payload["weeklyLimit"]), 684 current_progress=int(payload["currentProgress"]), 685 daily_progress=int(payload["dailyProgress"]), 686 needed=int(payload["progressToNextLevel"]), 687 next_level=int(payload["nextLevelAt"]), 688 )
776 def deserialize_milestone( 777 self, payload: typedefs.JSONObject 778 ) -> milestones.Milestone: 779 start_date: typing.Optional[datetime.datetime] = None 780 if raw_start_date := payload.get("startDate"): 781 start_date = time.clean_date(raw_start_date) 782 783 end_date: typing.Optional[datetime.datetime] = None 784 if raw_end_date := payload.get("endDate"): 785 end_date = time.clean_date(raw_end_date) 786 787 rewards: typing.Optional[ 788 collections.Collection[milestones.MilestoneReward] 789 ] = None 790 if raw_rewards := payload.get("rewards"): 791 rewards = [ 792 self._deserialize_milestone_rewards(reward) for reward in raw_rewards 793 ] 794 795 activities: typing.Optional[ 796 collections.Sequence[milestones.MilestoneActivity] 797 ] = None 798 if raw_activities := payload.get("activities"): 799 activities = [ 800 self._deserialize_milestone_activity(active) 801 for active in raw_activities 802 ] 803 804 quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None 805 if raw_quests := payload.get("availableQuests"): 806 quests = [ 807 self._deserialize_milestone_available_quest(quest) 808 for quest in raw_quests 809 ] 810 811 vendors: typing.Optional[ 812 collections.Sequence[milestones.MilestoneVendor] 813 ] = None 814 if raw_vendors := payload.get("vendors"): 815 vendors = [ 816 milestones.MilestoneVendor( 817 vendor_hash=vendor["vendorHash"], 818 preview_itemhash=vendor.get("previewItemHash"), 819 ) 820 for vendor in raw_vendors 821 ] 822 823 return milestones.Milestone( 824 hash=payload["milestoneHash"], 825 start_date=start_date, 826 end_date=end_date, 827 order=payload["order"], 828 rewards=rewards, 829 available_quests=quests, 830 activities=activities, 831 vendors=vendors, 832 )
886 def deserialize_character_progressions( 887 self, payload: typedefs.JSONObject 888 ) -> character.CharacterProgression: 889 progressions_ = { 890 int(prog_id): self.deserialize_progressions(prog) 891 for prog_id, prog in payload["progressions"].items() 892 } 893 894 factions = { 895 int(faction_id): self._deserialize_factions(faction) 896 for faction_id, faction in payload["factions"].items() 897 } 898 899 milestones_ = { 900 int(milestone_hash): self.deserialize_milestone(milestone) 901 for milestone_hash, milestone in payload["milestones"].items() 902 } 903 904 uninstanced_item_objectives = { 905 int(item_hash): [self.deserialize_objectives(ins) for ins in obj] 906 for item_hash, obj in payload["uninstancedItemObjectives"].items() 907 } 908 909 artifact = payload["seasonalArtifact"] 910 seasonal_artifact = season.CharacterScopedArtifact( 911 hash=artifact["artifactHash"], 912 points_used=artifact["pointsUsed"], 913 reset_count=artifact["resetCount"], 914 tiers=[ 915 self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"] 916 ], 917 ) 918 checklists = payload["checklists"] 919 920 return character.CharacterProgression( 921 progressions=progressions_, 922 factions=factions, 923 checklists=checklists, 924 milestones=milestones_, 925 seasonal_artifact=seasonal_artifact, 926 uninstanced_item_objectives=uninstanced_item_objectives, 927 )
929 def deserialize_character_progressions_mapping( 930 self, payload: typedefs.JSONObject 931 ) -> collections.Mapping[int, character.CharacterProgression]: 932 character_progressions: collections.Mapping[ 933 int, character.CharacterProgression 934 ] = {} 935 for char_id, data in payload["data"].items(): 936 # A little hack to stop mypy complaining about Mapping <-> dict 937 character_progressions[int(char_id)] = self.deserialize_character_progressions(data) # type: ignore[index] 938 return character_progressions
940 def deserialize_characters_records( 941 self, 942 payload: typedefs.JSONObject, 943 ) -> collections.Mapping[int, records.CharacterRecord]: 944 945 return { 946 int(rec_id): self.deserialize_character_records( 947 rec, record_hashes=payload.get("featuredRecordHashes") 948 ) 949 for rec_id, rec in payload["records"].items() 950 }
952 def deserialize_profile_records( 953 self, payload: typedefs.JSONObject 954 ) -> collections.Mapping[int, records.Record]: 955 raw_profile_records = payload["data"] 956 scores = records.RecordScores( 957 current_score=raw_profile_records["score"], 958 legacy_score=raw_profile_records["legacyScore"], 959 lifetime_score=raw_profile_records["lifetimeScore"], 960 ) 961 return { 962 int(record_id): self.deserialize_records( 963 record, 964 scores, 965 categories_hash=raw_profile_records["recordCategoriesRootNodeHash"], 966 seals_hash=raw_profile_records["recordSealsRootNodeHash"], 967 ) 968 for record_id, record in raw_profile_records["records"].items() 969 }
1006 def deserialize_craftables_component( 1007 self, payload: typedefs.JSONObject 1008 ) -> components.CraftablesComponent: 1009 return components.CraftablesComponent( 1010 net=self._net, 1011 craftables={ 1012 int(item_id): self._deserialize_craftable_item(item) 1013 for item_id, item in payload["craftables"].items() 1014 if item is not None 1015 }, 1016 crafting_root_node_hash=payload["craftingRootNodeHash"], 1017 )
1019 def deserialize_components( # noqa: C901 Too complex. 1020 self, payload: typedefs.JSONObject 1021 ) -> components.Component: 1022 1023 profile_: typing.Optional[profile.Profile] = None 1024 if raw_profile := payload.get("profile"): 1025 profile_ = self.deserialize_profile(raw_profile) 1026 1027 profile_progression: typing.Optional[profile.ProfileProgression] = None 1028 if raw_profile_progression := payload.get("profileProgression"): 1029 profile_progression = self.deserialize_profile_progression( 1030 raw_profile_progression 1031 ) 1032 1033 profile_currencies: typing.Optional[ 1034 collections.Sequence[profile.ProfileItemImpl] 1035 ] = None 1036 if raw_profile_currencies := payload.get("profileCurrencies"): 1037 if "data" in raw_profile_currencies: 1038 profile_currencies = self.deserialize_profile_items( 1039 raw_profile_currencies["data"] 1040 ) 1041 1042 profile_inventories: typing.Optional[ 1043 collections.Sequence[profile.ProfileItemImpl] 1044 ] = None 1045 if raw_profile_inventories := payload.get("profileInventory"): 1046 if "data" in raw_profile_inventories: 1047 profile_inventories = self.deserialize_profile_items( 1048 raw_profile_inventories["data"] 1049 ) 1050 1051 profile_records: typing.Optional[ 1052 collections.Mapping[int, records.Record] 1053 ] = None 1054 1055 if raw_profile_records_ := payload.get("profileRecords"): 1056 profile_records = self.deserialize_profile_records(raw_profile_records_) 1057 1058 characters: typing.Optional[typing.Mapping[int, character.Character]] = None 1059 if raw_characters := payload.get("characters"): 1060 characters = self.deserialize_characters(raw_characters) 1061 1062 character_records: typing.Optional[ 1063 collections.Mapping[int, records.CharacterRecord] 1064 ] = None 1065 1066 if raw_character_records := payload.get("characterRecords"): 1067 # Had to do it in two steps.. 1068 to_update: typedefs.JSONObject = {} 1069 for _, data in raw_character_records["data"].items(): 1070 for record_id, record in data.items(): 1071 to_update[record_id] = record 1072 1073 character_records = { 1074 int(rec_id): self.deserialize_character_records( 1075 rec, record_hashes=to_update.get("featuredRecordHashes") 1076 ) 1077 for rec_id, rec in to_update["records"].items() 1078 } 1079 1080 character_equipments: typing.Optional[ 1081 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1082 ] = None 1083 if raw_character_equips := payload.get("characterEquipment"): 1084 character_equipments = self.deserialize_character_equipments( 1085 raw_character_equips 1086 ) 1087 1088 character_inventories: typing.Optional[ 1089 collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]] 1090 ] = None 1091 if raw_character_inventories := payload.get("characterInventories"): 1092 if "data" in raw_character_inventories: 1093 character_inventories = self.deserialize_character_equipments( 1094 raw_character_inventories 1095 ) 1096 1097 character_activities: typing.Optional[ 1098 collections.Mapping[int, activity.CharacterActivity] 1099 ] = None 1100 if raw_char_acts := payload.get("characterActivities"): 1101 character_activities = self.deserialize_character_activities(raw_char_acts) 1102 1103 character_render_data: typing.Optional[ 1104 collections.Mapping[int, character.RenderedData] 1105 ] = None 1106 if raw_character_render_data := payload.get("characterRenderData"): 1107 character_render_data = self.deserialize_characters_render_data( 1108 raw_character_render_data 1109 ) 1110 1111 character_progressions: typing.Optional[ 1112 collections.Mapping[int, character.CharacterProgression] 1113 ] = None 1114 1115 if raw_character_progressions := payload.get("characterProgressions"): 1116 character_progressions = self.deserialize_character_progressions_mapping( 1117 raw_character_progressions 1118 ) 1119 1120 profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None 1121 if raw_profile_string_vars := payload.get("profileStringVariables"): 1122 profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"] 1123 1124 character_string_vars: typing.Optional[ 1125 collections.Mapping[int, collections.Mapping[int, int]] 1126 ] = None 1127 if raw_character_string_vars := payload.get("characterStringVariables"): 1128 character_string_vars = { 1129 int(char_id): data["integerValuesByHash"] 1130 for char_id, data in raw_character_string_vars["data"].items() 1131 } 1132 1133 metrics: typing.Optional[ 1134 collections.Sequence[ 1135 collections.Mapping[ 1136 int, tuple[bool, typing.Optional[records.Objective]] 1137 ] 1138 ] 1139 ] = None 1140 root_node_hash: typing.Optional[int] = None 1141 1142 if raw_metrics := payload.get("metrics"): 1143 root_node_hash = raw_metrics["data"]["metricsRootNodeHash"] 1144 metrics = [ 1145 { 1146 int(metrics_hash): ( 1147 data["invisible"], 1148 self.deserialize_objectives(data["objectiveProgress"]) 1149 if "objectiveProgress" in data 1150 else None, 1151 ) 1152 for metrics_hash, data in raw_metrics["data"]["metrics"].items() 1153 } 1154 ] 1155 transitory: typing.Optional[fireteams.FireteamParty] = None 1156 if raw_transitory := payload.get("profileTransitoryData"): 1157 if "data" in raw_transitory: 1158 transitory = self.deserialize_fireteam_party(raw_transitory["data"]) 1159 1160 item_components: typing.Optional[components.ItemsComponent] = None 1161 if raw_item_components := payload.get("itemComponents"): 1162 item_components = self.deserialize_items_component(raw_item_components) 1163 1164 profile_plugsets: typing.Optional[ 1165 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1166 ] = None 1167 1168 if raw_profile_plugs := payload.get("profilePlugSets"): 1169 profile_plugsets = { 1170 int(index): [self.deserialize_plug_item_state(state) for state in data] 1171 for index, data in raw_profile_plugs["data"]["plugs"].items() 1172 } 1173 1174 character_plugsets: typing.Optional[ 1175 collections.Mapping[ 1176 int, collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1177 ] 1178 ] = None 1179 if raw_char_plugsets := payload.get("characterPlugSets"): 1180 character_plugsets = { 1181 int(char_id): { 1182 int(index): [ 1183 self.deserialize_plug_item_state(state) for state in data 1184 ] 1185 for index, data in inner["plugs"].items() 1186 } 1187 for char_id, inner in raw_char_plugsets["data"].items() 1188 } 1189 1190 character_collectibles: typing.Optional[ 1191 collections.Mapping[int, items.Collectible] 1192 ] = None 1193 if raw_character_collectibles := payload.get("characterCollectibles"): 1194 character_collectibles = { 1195 int(char_id): self._deserialize_collectible(data) 1196 for char_id, data in raw_character_collectibles["data"].items() 1197 } 1198 1199 profile_collectibles: typing.Optional[items.Collectible] = None 1200 if raw_profile_collectibles := payload.get("profileCollectibles"): 1201 profile_collectibles = self._deserialize_collectible( 1202 raw_profile_collectibles["data"] 1203 ) 1204 1205 profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1206 if raw_profile_nodes := payload.get("profilePresentationNodes"): 1207 profile_nodes = { 1208 int(node_hash): self._deserialize_node(node) 1209 for node_hash, node in raw_profile_nodes["data"]["nodes"].items() 1210 } 1211 1212 character_nodes: typing.Optional[ 1213 collections.Mapping[int, collections.Mapping[int, records.Node]] 1214 ] = None 1215 if raw_character_nodes := payload.get("characterPresentationNodes"): 1216 character_nodes = { 1217 int(char_id): { 1218 int(node_hash): self._deserialize_node(node) 1219 for node_hash, node in each_character["nodes"].items() 1220 } 1221 for char_id, each_character in raw_character_nodes["data"].items() 1222 } 1223 1224 platform_silver: typing.Optional[ 1225 collections.Mapping[str, profile.ProfileItemImpl] 1226 ] = None 1227 if raw_platform_silver := payload.get("platformSilver"): 1228 if "data" in raw_platform_silver: 1229 platform_silver = { 1230 platform_name: self.deserialize_profile_item(item) 1231 for platform_name, item in raw_platform_silver["data"][ 1232 "platformSilver" 1233 ].items() 1234 } 1235 1236 character_currency_lookups: typing.Optional[ 1237 collections.Mapping[int, collections.Sequence[items.Currency]] 1238 ] = None 1239 if raw_char_lookups := payload.get("characterCurrencyLookups"): 1240 if "data" in raw_char_lookups: 1241 character_currency_lookups = { 1242 int(char_id): self._deserialize_currencies(currencie) 1243 for char_id, currencie in raw_char_lookups["data"].items() 1244 } 1245 1246 character_craftables: typing.Optional[ 1247 collections.Mapping[int, components.CraftablesComponent] 1248 ] = None 1249 if raw_character_craftables := payload.get("characterCraftables"): 1250 1251 if "data" in raw_character_craftables: 1252 character_craftables = { 1253 int(char_id): self.deserialize_craftables_component(craftable) 1254 for char_id, craftable in raw_character_craftables["data"].items() 1255 } 1256 1257 return components.Component( 1258 profiles=profile_, 1259 profile_progression=profile_progression, 1260 profile_currencies=profile_currencies, 1261 profile_inventories=profile_inventories, 1262 profile_records=profile_records, 1263 characters=characters, 1264 character_records=character_records, 1265 character_equipments=character_equipments, 1266 character_inventories=character_inventories, 1267 character_activities=character_activities, 1268 character_render_data=character_render_data, 1269 character_progressions=character_progressions, 1270 profile_string_variables=profile_string_vars, 1271 character_string_variables=character_string_vars, 1272 metrics=metrics, 1273 root_node_hash=root_node_hash, 1274 transitory=transitory, 1275 item_components=item_components, 1276 profile_plugsets=profile_plugsets, 1277 character_plugsets=character_plugsets, 1278 character_collectibles=character_collectibles, 1279 profile_collectibles=profile_collectibles, 1280 profile_nodes=profile_nodes, 1281 character_nodes=character_nodes, 1282 platform_silver=platform_silver, 1283 character_currency_lookups=character_currency_lookups, 1284 character_craftables=character_craftables, 1285 )
Deserialize a JSON payload of Bungie.net profile components information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Component: A component implementation that includes all other components of the deserialized payload.
1287 def deserialize_items_component( 1288 self, payload: typedefs.JSONObject 1289 ) -> components.ItemsComponent: 1290 instances: typing.Optional[ 1291 collections.Sequence[collections.Mapping[int, items.ItemInstance]] 1292 ] = None 1293 if raw_instances := payload.get("instances"): 1294 instances = [ 1295 { 1296 int(ins_id): self.deserialize_instanced_item(item) 1297 for ins_id, item in raw_instances["data"].items() 1298 } 1299 ] 1300 1301 render_data: typing.Optional[ 1302 collections.Mapping[int, tuple[bool, dict[int, int]]] 1303 ] = None 1304 if raw_render_data := payload.get("renderData"): 1305 render_data = { 1306 int(ins_id): (data["useCustomDyes"], data["artRegions"]) 1307 for ins_id, data in raw_render_data["data"].items() 1308 } 1309 1310 stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None 1311 if raw_stats := payload.get("stats"): 1312 builder: collections.Mapping[int, items.ItemStatsView] = {} 1313 for ins_id, stat in raw_stats["data"].items(): 1314 for _, items_ in stat.items(): 1315 builder[int(ins_id)] = self.deserialize_item_stats_view(items_) # type: ignore[index] 1316 stats = builder 1317 1318 sockets: typing.Optional[ 1319 collections.Mapping[int, collections.Sequence[items.ItemSocket]] 1320 ] = None 1321 if raw_sockets := payload.get("sockets"): 1322 sockets = { 1323 int(ins_id): [ 1324 self.deserialize_item_socket(socket) for socket in item["sockets"] 1325 ] 1326 for ins_id, item in raw_sockets["data"].items() 1327 } 1328 1329 objeectives: typing.Optional[ 1330 collections.Mapping[int, collections.Sequence[records.Objective]] 1331 ] = None 1332 if raw_objectives := payload.get("objectives"): 1333 objeectives = { 1334 int(ins_id): [self.deserialize_objectives(objective)] 1335 for ins_id, data in raw_objectives["data"].items() 1336 for objective in data["objectives"] 1337 } 1338 1339 perks: typing.Optional[ 1340 collections.Mapping[int, collections.Collection[items.ItemPerk]] 1341 ] = None 1342 if raw_perks := payload.get("perks"): 1343 perks = { 1344 int(ins_id): [ 1345 self.deserialize_item_perk(perk) for perk in item["perks"] 1346 ] 1347 for ins_id, item in raw_perks["data"].items() 1348 } 1349 1350 plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None 1351 if raw_plug_states := payload.get("plugStates"): 1352 pending_states: list[items.PlugItemState] = [] 1353 for _, plug in raw_plug_states["data"].items(): 1354 pending_states.append(self.deserialize_plug_item_state(plug)) 1355 plug_states = pending_states 1356 1357 reusable_plugs: typing.Optional[ 1358 collections.Mapping[int, collections.Sequence[items.PlugItemState]] 1359 ] = None 1360 if raw_re_plugs := payload.get("reusablePlugs"): 1361 reusable_plugs = { 1362 int(ins_id): [ 1363 self.deserialize_plug_item_state(state) for state in inner 1364 ] 1365 for ins_id, plug in raw_re_plugs["data"].items() 1366 for inner in list(plug["plugs"].values()) 1367 } 1368 1369 plug_objectives: typing.Optional[ 1370 collections.Mapping[ 1371 int, collections.Mapping[int, collections.Collection[records.Objective]] 1372 ] 1373 ] = None 1374 if raw_plug_objectives := payload.get("plugObjectives"): 1375 plug_objectives = { 1376 int(ins_id): { 1377 int(obj_hash): [self.deserialize_objectives(obj) for obj in objs] 1378 for obj_hash, objs in inner["objectivesPerPlug"].items() 1379 } 1380 for ins_id, inner in raw_plug_objectives["data"].items() 1381 } 1382 1383 return components.ItemsComponent( 1384 sockets=sockets, 1385 stats=stats, 1386 render_data=render_data, 1387 instances=instances, 1388 objectives=objeectives, 1389 perks=perks, 1390 plug_states=plug_states, 1391 reusable_plugs=reusable_plugs, 1392 plug_objectives=plug_objectives, 1393 )
Deserialize a JSON objects within the itemComponents key.`
1395 def deserialize_character_component( # type: ignore[call-arg] 1396 self, payload: typedefs.JSONObject 1397 ) -> components.CharacterComponent: 1398 1399 character_: typing.Optional[character.Character] = None 1400 if raw_singuler_character := payload.get("character"): 1401 character_ = self.deserialize_character(raw_singuler_character["data"]) 1402 1403 inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1404 if raw_inventory := payload.get("inventory"): 1405 if "data" in raw_inventory: 1406 inventory = self.deserialize_profile_items(raw_inventory["data"]) 1407 1408 activities: typing.Optional[activity.CharacterActivity] = None 1409 if raw_activities := payload.get("activities"): 1410 activities = self.deserialize_character_activity(raw_activities["data"]) 1411 1412 equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None 1413 if raw_equipments := payload.get("equipment"): 1414 equipment = self.deserialize_profile_items(raw_equipments["data"]) 1415 1416 progressions_: typing.Optional[character.CharacterProgression] = None 1417 if raw_progressions := payload.get("progressions"): 1418 progressions_ = self.deserialize_character_progressions( 1419 raw_progressions["data"] 1420 ) 1421 1422 render_data: typing.Optional[character.RenderedData] = None 1423 if raw_render_data := payload.get("renderData"): 1424 render_data = self.deserialize_character_render_data( 1425 raw_render_data["data"] 1426 ) 1427 1428 character_records: typing.Optional[ 1429 collections.Mapping[int, records.CharacterRecord] 1430 ] = None 1431 if raw_char_records := payload.get("records"): 1432 character_records = self.deserialize_characters_records( 1433 raw_char_records["data"] 1434 ) 1435 1436 item_components: typing.Optional[components.ItemsComponent] = None 1437 if raw_item_components := payload.get("itemComponents"): 1438 item_components = self.deserialize_items_component(raw_item_components) 1439 1440 nodes: typing.Optional[collections.Mapping[int, records.Node]] = None 1441 if raw_nodes := payload.get("presentationNodes"): 1442 nodes = { 1443 int(node_hash): self._deserialize_node(node) 1444 for node_hash, node in raw_nodes["data"]["nodes"].items() 1445 } 1446 1447 collectibles: typing.Optional[items.Collectible] = None 1448 if raw_collectibles := payload.get("collectibles"): 1449 collectibles = self._deserialize_collectible(raw_collectibles["data"]) 1450 1451 currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None 1452 if raw_currencies := payload.get("currencyLookups"): 1453 if "data" in raw_currencies: 1454 currency_lookups = self._deserialize_currencies(raw_currencies) 1455 1456 return components.CharacterComponent( 1457 activities=activities, 1458 equipment=equipment, 1459 inventory=inventory, 1460 progressions=progressions_, 1461 render_data=render_data, 1462 character=character_, 1463 character_records=character_records, 1464 profile_records=None, 1465 item_components=item_components, 1466 currency_lookups=currency_lookups, 1467 collectibles=collectibles, 1468 nodes=nodes, 1469 )
Deserialize a JSON payload of Destiny 2 character component.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.CharacterComponent: A character component.
1497 def deserialize_inventory_results( 1498 self, payload: typedefs.JSONObject 1499 ) -> iterators.FlatIterator[entity.SearchableEntity]: 1500 suggested_words: list[str] = payload["suggestedWords"] 1501 1502 def _check_unknown(s: str) -> undefined.UndefinedOr[str]: 1503 return s if not typedefs.is_unknown(s) else undefined.Undefined 1504 1505 return iterators.FlatIterator( 1506 [ 1507 entity.SearchableEntity( 1508 net=self._net, 1509 hash=data["hash"], 1510 entity_type=data["entityType"], 1511 weight=data["weight"], 1512 suggested_words=suggested_words, 1513 name=data["displayProperties"]["name"], 1514 has_icon=data["displayProperties"]["hasIcon"], 1515 description=_check_unknown( 1516 data["displayProperties"]["description"] 1517 ), 1518 icon=assets.Image(data["displayProperties"]["icon"]), 1519 ) 1520 for data in payload["results"]["results"] 1521 ] 1522 )
Deserialize results of searched Destiny2 entities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]: An iterator over the found searched entities.
1551 def deserialize_inventory_entity( # noqa: C901 Too complex. 1552 self, payload: typedefs.JSONObject, / 1553 ) -> entity.InventoryEntity: 1554 1555 props = self._set_entity_attrs(payload) 1556 objects = self._deserialize_inventory_item_objects(payload) 1557 1558 collectible_hash: typing.Optional[int] = None 1559 if raw_collectible_hash := payload.get("collectibleHash"): 1560 collectible_hash = int(raw_collectible_hash) 1561 1562 secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1563 if raw_second_icon := payload.get("secondaryIcon"): 1564 secondary_icon = assets.Image(raw_second_icon) 1565 1566 secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1567 if raw_second_overlay := payload.get("secondaryOverlay"): 1568 secondary_overlay = assets.Image(raw_second_overlay) 1569 1570 secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1571 if raw_second_special := payload.get("secondarySpecial"): 1572 secondary_special = assets.Image(raw_second_special) 1573 1574 screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined 1575 if raw_screenshot := payload.get("screenshot"): 1576 screenshot = assets.Image(raw_screenshot) 1577 1578 watermark_icon: typing.Optional[assets.Image] = None 1579 if raw_watermark_icon := payload.get("iconWatermark"): 1580 watermark_icon = assets.Image(raw_watermark_icon) 1581 1582 watermark_shelved: typing.Optional[assets.Image] = None 1583 if raw_watermark_shelved := payload.get("iconWatermarkShelved"): 1584 watermark_shelved = assets.Image(raw_watermark_shelved) 1585 1586 about: undefined.UndefinedOr[str] = undefined.Undefined 1587 if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown( 1588 raw_about 1589 ): 1590 about = raw_about 1591 1592 ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined 1593 if ( 1594 raw_ui_style := payload.get("uiItemDisplayStyle") 1595 ) and not typedefs.is_unknown(raw_ui_style): 1596 ui_item_style = raw_ui_style 1597 1598 tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined 1599 if ( 1600 raw_tier_and_name := payload.get("itemTypeAndTierDisplayName") 1601 ) and not typedefs.is_unknown(raw_tier_and_name): 1602 tier_and_name = raw_tier_and_name 1603 1604 type_name: undefined.UndefinedOr[str] = undefined.Undefined 1605 if ( 1606 raw_type_name := payload.get("itemTypeDisplayName") 1607 ) and not typedefs.is_unknown(raw_type_name): 1608 type_name = raw_type_name 1609 1610 display_source: undefined.UndefinedOr[str] = undefined.Undefined 1611 if ( 1612 raw_display_source := payload.get("displaySource") 1613 ) and not typedefs.is_unknown(raw_display_source): 1614 display_source = raw_display_source 1615 1616 lorehash: typing.Optional[int] = None 1617 if raw_lore_hash := payload.get("loreHash"): 1618 lorehash = int(raw_lore_hash) 1619 1620 summary_hash: typing.Optional[int] = None 1621 if raw_summary_hash := payload.get("summaryItemHash"): 1622 summary_hash = raw_summary_hash 1623 1624 breaker_type_hash: typing.Optional[int] = None 1625 if raw_breaker_type_hash := payload.get("breakerTypeHash"): 1626 breaker_type_hash = int(raw_breaker_type_hash) 1627 1628 damage_types: typing.Optional[collections.Sequence[int]] = None 1629 if raw_damage_types := payload.get("damageTypes"): 1630 damage_types = [int(type_) for type_ in raw_damage_types] 1631 1632 damagetype_hashes: typing.Optional[collections.Sequence[int]] = None 1633 if raw_damagetype_hashes := payload.get("damageTypeHashes"): 1634 damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes] 1635 1636 default_damagetype_hash: typing.Optional[int] = None 1637 if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"): 1638 default_damagetype_hash = int(raw_defaultdmg_hash) 1639 1640 emblem_objective_hash: typing.Optional[int] = None 1641 if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"): 1642 emblem_objective_hash = int(raw_emblem_obj_hash) 1643 1644 tier_type: typing.Optional[enums.TierType] = None 1645 tier: typing.Optional[enums.ItemTier] = None 1646 bucket_hash: typing.Optional[int] = None 1647 recovery_hash: typing.Optional[int] = None 1648 tier_name: undefined.UndefinedOr[str] = undefined.Undefined 1649 isinstance_item: bool = False 1650 expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined 1651 expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined 1652 suppress_expiration: bool = False 1653 max_stack_size: typing.Optional[int] = None 1654 stack_label: undefined.UndefinedOr[str] = undefined.Undefined 1655 1656 if inventory := payload.get("inventory"): 1657 tier_type = enums.TierType(int(inventory["tierType"])) 1658 tier = enums.ItemTier(int(inventory["tierTypeHash"])) 1659 bucket_hash = int(inventory["bucketTypeHash"]) 1660 recovery_hash = int(inventory["recoveryBucketTypeHash"]) 1661 tier_name = inventory["tierTypeName"] 1662 isinstance_item = inventory["isInstanceItem"] 1663 suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"] 1664 max_stack_size = int(inventory["maxStackSize"]) 1665 1666 try: 1667 stack_label = inventory["stackUniqueLabel"] 1668 except KeyError: 1669 pass 1670 1671 return entity.InventoryEntity( 1672 net=self._net, 1673 collectible_hash=collectible_hash, 1674 name=props.name, 1675 about=about, 1676 emblem_objective_hash=emblem_objective_hash, 1677 suppress_expiration=suppress_expiration, 1678 max_stack_size=max_stack_size, 1679 stack_label=stack_label, 1680 tier=tier, 1681 tier_type=tier_type, 1682 tier_name=tier_name, 1683 bucket_hash=bucket_hash, 1684 recovery_bucket_hash=recovery_hash, 1685 isinstance_item=isinstance_item, 1686 expire_in_orbit_message=expire_in_orbit_message, 1687 expiration_tooltip=expire_tool_tip, 1688 lore_hash=lorehash, 1689 type_and_tier_name=tier_and_name, 1690 summary_hash=summary_hash, 1691 ui_display_style=ui_item_style, 1692 type_name=type_name, 1693 breaker_type_hash=breaker_type_hash, 1694 description=props.description, 1695 display_source=display_source, 1696 hash=props.hash, 1697 damage_types=damage_types, 1698 index=props.index, 1699 icon=props.icon, 1700 has_icon=props.has_icon, 1701 screenshot=screenshot, 1702 watermark_icon=watermark_icon, 1703 watermark_shelved=watermark_shelved, 1704 secondary_icon=secondary_icon, 1705 secondary_overlay=secondary_overlay, 1706 secondary_special=secondary_special, 1707 type=enums.ItemType(int(payload["itemType"])), 1708 trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])], 1709 trait_ids=[trait for trait in payload.get("traitIds", [])], 1710 category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]], 1711 item_class=enums.Class(int(payload["classType"])), 1712 sub_type=enums.ItemSubType(int(payload["itemSubType"])), 1713 breaker_type=int(payload["breakerType"]), 1714 default_damagetype=int(payload["defaultDamageType"]), 1715 default_damagetype_hash=default_damagetype_hash, 1716 damagetype_hashes=damagetype_hashes, 1717 tooltip_notifications=payload["tooltipNotifications"], 1718 not_transferable=payload["nonTransferrable"], 1719 allow_actions=payload["allowActions"], 1720 is_equippable=payload["equippable"], 1721 objects=objects, 1722 background_colors=payload.get("backgroundColor", {}), 1723 season_hash=payload.get("seasonHash"), 1724 has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"], 1725 )
Deserialize a JSON payload of an inventory entity item information.
This can be any item from DestinyInventoryItemDefinition definition.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.InventoryEntity: An entity item.
1727 def deserialize_objective_entity( 1728 self, payload: typedefs.JSONObject, / 1729 ) -> entity.ObjectiveEntity: 1730 props = self._set_entity_attrs(payload) 1731 return entity.ObjectiveEntity( 1732 net=self._net, 1733 hash=props.hash, 1734 index=props.index, 1735 description=props.description, 1736 name=props.name, 1737 has_icon=props.has_icon, 1738 icon=props.icon, 1739 unlock_value_hash=payload["unlockValueHash"], 1740 completion_value=payload["completionValue"], 1741 scope=entity.GatingScope(int(payload["scope"])), 1742 location_hash=payload["locationHash"], 1743 allowed_negative_value=payload["allowNegativeValue"], 1744 allowed_value_change=payload["allowValueChangeWhenCompleted"], 1745 counting_downward=payload["isCountingDownward"], 1746 value_style=entity.ValueUIStyle(int(payload["valueStyle"])), 1747 progress_description=payload["progressDescription"], 1748 perks=payload["perks"], 1749 stats=payload["stats"], 1750 minimum_visibility=payload["minimumVisibilityThreshold"], 1751 allow_over_completion=payload["allowOvercompletion"], 1752 show_value_style=payload["showValueOnComplete"], 1753 display_only_objective=payload["isDisplayOnlyObjective"], 1754 complete_value_style=entity.ValueUIStyle( 1755 int(payload["completedValueStyle"]) 1756 ), 1757 progress_value_style=entity.ValueUIStyle( 1758 int(payload["inProgressValueStyle"]) 1759 ), 1760 ui_label=payload["uiLabel"], 1761 ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])), 1762 )
Deserialize a JSON payload of an objective entity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ObjectiveEntity: An objective entity.
1790 def deserialize_activity( 1791 self, 1792 payload: typedefs.JSONObject, 1793 /, 1794 ) -> activity.Activity: 1795 period = time.clean_date(payload["period"]) 1796 details = payload["activityDetails"] 1797 ref_id = int(details["referenceId"]) 1798 instance_id = int(details["instanceId"]) 1799 mode = enums.GameMode(details["mode"]) 1800 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1801 is_private = details["isPrivate"] 1802 membership_type = enums.MembershipType(int(details["membershipType"])) 1803 1804 # Since we're using the same fields for post activity method 1805 # this check is required since post activity doesn't values values 1806 values = self._deserialize_activity_values(payload["values"]) 1807 1808 return activity.Activity( 1809 net=self._net, 1810 hash=ref_id, 1811 instance_id=instance_id, 1812 mode=mode, 1813 modes=modes, 1814 is_private=is_private, 1815 membership_type=membership_type, 1816 occurred_at=period, 1817 values=values, 1818 )
Deserialize a JSON payload of an activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Activity: An activity.
1820 def deserialize_activities( 1821 self, payload: typedefs.JSONObject 1822 ) -> iterators.FlatIterator[activity.Activity]: 1823 return iterators.FlatIterator( 1824 [ 1825 self.deserialize_activity(activity_) 1826 for activity_ in payload["activities"] 1827 ] 1828 )
Deserialize a JSON payload of an array of activity history information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
1830 def deserialize_extended_weapon_values( 1831 self, payload: typedefs.JSONObject 1832 ) -> activity.ExtendedWeaponValues: 1833 1834 assists: typing.Optional[int] = None 1835 if raw_assists := payload["values"].get("uniqueWeaponAssists"): 1836 assists = raw_assists["basic"]["value"] 1837 assists_damage: typing.Optional[int] = None 1838 1839 if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"): 1840 assists_damage = raw_assists_damage["basic"]["value"] 1841 1842 return activity.ExtendedWeaponValues( 1843 reference_id=int(payload["referenceId"]), 1844 kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"], 1845 precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][ 1846 "value" 1847 ], 1848 assists=assists, 1849 assists_damage=assists_damage, 1850 precision_kills_percentage=( 1851 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"], 1852 payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][ 1853 "displayValue" 1854 ], 1855 ), 1856 )
Deserialize values of extended weapons JSON object.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.ExtendedWeaponValues: Information about an extended weapon values.
1879 def deserialize_post_activity_player( 1880 self, payload: typedefs.JSONObject, / 1881 ) -> activity.PostActivityPlayer: 1882 player = payload["player"] 1883 1884 class_hash: typedefs.NoneOr[int] = None 1885 if (class_hash := player.get("classHash")) is not None: 1886 class_hash = class_hash 1887 1888 race_hash: typedefs.NoneOr[int] = None 1889 if (race_hash := player.get("raceHash")) is not None: 1890 race_hash = race_hash 1891 1892 gender_hash: typedefs.NoneOr[int] = None 1893 if (gender_hash := player.get("genderHash")) is not None: 1894 gender_hash = gender_hash 1895 1896 character_class: undefined.UndefinedOr[str] = undefined.Undefined 1897 if ( 1898 character_class := player.get("characterClass") 1899 ) and not typedefs.is_unknown(character_class): 1900 character_class = character_class 1901 1902 character_level: typedefs.NoneOr[int] = None 1903 if (character_level := player.get("characterLevel")) is not None: 1904 character_level = character_level 1905 1906 return activity.PostActivityPlayer( 1907 standing=int(payload["standing"]), 1908 score=int(payload["score"]["basic"]["value"]), 1909 character_id=payload["characterId"], 1910 destiny_user=self.deserialize_destiny_membership( 1911 payload["player"]["destinyUserInfo"] 1912 ), 1913 character_class=character_class, 1914 character_level=character_level, 1915 race_hash=race_hash, 1916 gender_hash=gender_hash, 1917 class_hash=class_hash, 1918 light_level=int(payload["player"]["lightLevel"]), 1919 emblem_hash=int(payload["player"]["emblemHash"]), 1920 values=self._deserialize_activity_values(payload["values"]), 1921 extended_values=self._deserialize_extended_values(payload["extended"]), 1922 )
Deserialize a JSON payload of a post activity player information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivityPlayer: A post activity player object.
1934 def deserialize_post_activity( 1935 self, payload: typedefs.JSONObject 1936 ) -> activity.PostActivity: 1937 period = time.clean_date(payload["period"]) 1938 details = payload["activityDetails"] 1939 ref_id = int(details["referenceId"]) 1940 instance_id = int(details["instanceId"]) 1941 mode = enums.GameMode(details["mode"]) 1942 modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]] 1943 is_private = details["isPrivate"] 1944 membership_type = enums.MembershipType(int(details["membershipType"])) 1945 return activity.PostActivity( 1946 net=self._net, 1947 hash=ref_id, 1948 membership_type=membership_type, 1949 instance_id=instance_id, 1950 mode=mode, 1951 modes=modes, 1952 is_private=is_private, 1953 occurred_at=period, 1954 starting_phase=int(payload["startingPhaseIndex"]), 1955 players=[ 1956 self.deserialize_post_activity_player(player) 1957 for player in payload["entries"] 1958 ], 1959 teams=[ 1960 self._deserialize_post_activity_team(team) for team in payload["teams"] 1961 ], 1962 )
Deserialize a JSON payload of a post activity information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.PostActivity: A post activity object.
2000 def deserialize_aggregated_activity( 2001 self, payload: typedefs.JSONObject 2002 ) -> activity.AggregatedActivity: 2003 return activity.AggregatedActivity( 2004 hash=int(payload["activityHash"]), 2005 values=self._deserialize_aggregated_activity_values(payload["values"]), 2006 )
Deserialize a JSON payload of an aggregated activity.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.AggregatedActivity: An aggregated activity object.
2008 def deserialize_aggregated_activities( 2009 self, payload: typedefs.JSONObject 2010 ) -> iterators.FlatIterator[activity.AggregatedActivity]: 2011 return iterators.FlatIterator( 2012 [ 2013 self.deserialize_aggregated_activity(activity) 2014 for activity in payload["activities"] 2015 ] 2016 )
Deserialize a JSON payload of an array of aggregated activities.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]: An iterator over aggregated activities objects.
2018 def deserialize_linked_profiles( 2019 self, payload: typedefs.JSONObject 2020 ) -> profile.LinkedProfile: 2021 bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"]) 2022 error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2023 profiles_vec: typing.MutableSequence[user.DestinyMembership] = [] 2024 2025 if raw_profile := payload.get("profiles"): 2026 for pfile in raw_profile: 2027 profiles_vec.append(self.deserialize_destiny_membership(pfile)) 2028 2029 if raw_profiles_with_errors := payload.get("profilesWithErrors"): 2030 for raw_error_pfile in raw_profiles_with_errors: 2031 if error_pfile := raw_error_pfile.get("infoCard"): 2032 error_profiles_vec.append( 2033 self.deserialize_destiny_membership(error_pfile) 2034 ) 2035 2036 return profile.LinkedProfile( 2037 net=self._net, 2038 bungie=bungie_user, 2039 profiles=profiles_vec, 2040 profiles_with_errors=error_profiles_vec, 2041 )
Deserialize a JSON payload of Bungie.net hard linked profile information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.LinkedProfile: A hard linked profile.
2057 def deserialize_public_milestone_content( 2058 self, payload: typedefs.JSONObject 2059 ) -> milestones.MilestoneContent: 2060 items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None 2061 if raw_categories := payload.get("itemCategories"): 2062 for item in raw_categories: 2063 title = undefined.Undefined 2064 if raw_title := item.get("title"): 2065 if raw_title != typedefs.Unknown: 2066 title = raw_title 2067 if raw_hashes := item.get("itemHashes"): 2068 hashes: collections.Sequence[int] = raw_hashes 2069 2070 items_categoris = milestones.MilestoneItems(title=title, hashes=hashes) 2071 2072 about = undefined.Undefined 2073 if (raw_about := payload["about"]) != typedefs.Unknown: 2074 about = raw_about 2075 2076 status = undefined.Undefined 2077 if (raw_status := payload["status"]) != typedefs.Unknown: 2078 status = raw_status 2079 2080 tips: typing.MutableSequence[undefined.UndefinedOr[str]] = [] 2081 if raw_tips := payload.get("tips"): 2082 for raw_tip in raw_tips: 2083 if raw_tip == typedefs.Unknown: 2084 raw_tip = undefined.Undefined 2085 tips.append(raw_tip) 2086 2087 return milestones.MilestoneContent( 2088 about=about, status=status, tips=tips, items=items_categoris 2089 )
Deserialize a JSON payload of milestone content information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.MilestoneContent: A milestone content.
2091 def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend: 2092 name = undefined.Undefined 2093 if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown: 2094 name = raw_name 2095 2096 bungie_user: typedefs.NoneOr[user.BungieUser] = None 2097 2098 if raw_bungie_user := payload.get("bungieNetUser"): 2099 bungie_user = self.deserialize_bungie_user(raw_bungie_user) 2100 2101 return friends.Friend( 2102 net=self._net, 2103 id=int(payload["lastSeenAsMembershipId"]), 2104 name=name, 2105 code=payload.get("bungieGlobalDisplayNameCode"), 2106 relationship=enums.Relationship(payload["relationship"]), 2107 user=bungie_user, 2108 online_status=enums.Presence(payload["onlineStatus"]), 2109 online_title=payload["onlineTitle"], 2110 type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]), 2111 )
Deserialize a JSON payload of a Bungie friend information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.Friend: A friend.
2113 def deserialize_friends( 2114 self, payload: typedefs.JSONObject 2115 ) -> collections.Sequence[friends.Friend]: 2116 mut_seq: typing.MutableSequence[friends.Friend] = [] 2117 if raw_friends := payload.get("friends"): 2118 for friend in raw_friends: 2119 mut_seq.append(self.deserialize_friend(friend)) 2120 return mut_seq
Deserialize a JSON sequence of Bungie friends information.
This is usually used to deserialize the incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Friend]: A sequence of friends.
2122 def deserialize_friend_requests( 2123 self, payload: typedefs.JSONObject 2124 ) -> friends.FriendRequestView: 2125 incoming: typing.MutableSequence[friends.Friend] = [] 2126 outgoing: typing.MutableSequence[friends.Friend] = [] 2127 2128 if raw_incoming_requests := payload.get("incomingRequests"): 2129 for incoming_request in raw_incoming_requests: 2130 incoming.append(self.deserialize_friend(incoming_request)) 2131 2132 if raw_outgoing_requests := payload.get("outgoingRequests"): 2133 for outgoing_request in raw_outgoing_requests: 2134 outgoing.append(self.deserialize_friend(outgoing_request)) 2135 2136 return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
Deserialize a JSON sequence of Bungie friend requests information.
This is used for incoming/outgoing friend requests.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.FriendRequestView]: A sequence of incoming and outgoing friends.
2161 def deserialize_fireteams( 2162 self, payload: typedefs.JSONObject 2163 ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]: 2164 fireteams_: typing.MutableSequence[fireteams.Fireteam] = [] 2165 2166 result: list[typedefs.JSONObject] 2167 if not (result := payload["results"]): 2168 return None 2169 for elem in result: 2170 fireteams_.append( 2171 self._set_fireteam_fields( 2172 elem, total_results=int(payload["totalResults"]) 2173 ) 2174 ) 2175 return fireteams_
Deserialize a JSON sequence of Bungie fireteams information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteam.
2177 def deserialize_fireteam_destiny_users( 2178 self, payload: typedefs.JSONObject 2179 ) -> fireteams.FireteamUser: 2180 destiny_obj = self.deserialize_destiny_membership(payload) 2181 # We could helpers.just return a DestinyMembership object but this is 2182 # missing the fireteam display name and id fields. 2183 return fireteams.FireteamUser( 2184 net=self._net, 2185 id=destiny_obj.id, 2186 code=destiny_obj.code, 2187 icon=destiny_obj.icon, 2188 types=destiny_obj.types, 2189 type=destiny_obj.type, 2190 is_public=destiny_obj.is_public, 2191 crossave_override=destiny_obj.crossave_override, 2192 name=destiny_obj.name, 2193 last_seen_name=destiny_obj.last_seen_name, 2194 fireteam_display_name=payload["FireteamDisplayName"], 2195 fireteam_membership_id=enums.MembershipType( 2196 payload["FireteamMembershipType"] 2197 ), 2198 )
Deserialize a JSON payload of Bungie fireteam destiny users information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamUser: A fireteam user.
2200 def deserialize_fireteam_members( 2201 self, payload: typedefs.JSONObject, *, alternatives: bool = False 2202 ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]: 2203 members_: list[fireteams.FireteamMember] = [] 2204 if members := payload.get("Members" if not alternatives else "Alternates"): 2205 for member in members: 2206 bungie_fields = self.deserialize_partial_bungie_user(member) 2207 members_fields = fireteams.FireteamMember( 2208 destiny_user=self.deserialize_fireteam_destiny_users(member), 2209 has_microphone=member["hasMicrophone"], 2210 character_id=int(member["characterId"]), 2211 date_joined=time.clean_date(member["dateJoined"]), 2212 last_platform_invite_date=time.clean_date( 2213 member["lastPlatformInviteAttemptDate"] 2214 ), 2215 last_platform_invite_result=int( 2216 member["lastPlatformInviteAttemptResult"] 2217 ), 2218 net=self._net, 2219 name=bungie_fields.name, 2220 id=bungie_fields.id, 2221 icon=bungie_fields.icon, 2222 is_public=bungie_fields.is_public, 2223 crossave_override=bungie_fields.crossave_override, 2224 types=bungie_fields.types, 2225 type=bungie_fields.type, 2226 ) 2227 members_.append(members_fields) 2228 else: 2229 return None 2230 return members_
Deserialize a JSON sequence of Bungie fireteam members information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - alternatives (
bool): If set toTrue, Then it will deserialize thealternativesdata in the payload. If not the it will just deserialize themembersdata.
Returns
typing.Optional[collections.Sequence[aiobungie.crates.FireteamUser]]: An optional sequence of the fireteam members.
2232 def deserialize_available_fireteams( 2233 self, 2234 data: typedefs.JSONObject, 2235 *, 2236 no_results: bool = False, 2237 ) -> typing.Union[ 2238 fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam] 2239 ]: 2240 fireteams_: list[fireteams.AvailableFireteam] = [] 2241 2242 # This needs to be used outside the results 2243 # JSON key. 2244 if no_results is True: 2245 payload = data 2246 2247 if result := payload.get("results"): 2248 2249 for fireteam in result: 2250 found_fireteams = self._set_fireteam_fields(fireteam["Summary"]) 2251 fireteams_fields = fireteams.AvailableFireteam( 2252 id=found_fireteams.id, 2253 group_id=found_fireteams.group_id, 2254 platform=found_fireteams.platform, 2255 activity_type=found_fireteams.activity_type, 2256 is_immediate=found_fireteams.is_immediate, 2257 is_public=found_fireteams.is_public, 2258 is_valid=found_fireteams.is_valid, 2259 owner_id=found_fireteams.owner_id, 2260 player_slot_count=found_fireteams.player_slot_count, 2261 available_player_slots=found_fireteams.available_player_slots, 2262 available_alternate_slots=found_fireteams.available_alternate_slots, 2263 title=found_fireteams.title, 2264 date_created=found_fireteams.date_created, 2265 locale=found_fireteams.locale, 2266 last_modified=found_fireteams.last_modified, 2267 total_results=found_fireteams.total_results, 2268 members=self.deserialize_fireteam_members(payload), 2269 alternatives=self.deserialize_fireteam_members( 2270 payload, alternatives=True 2271 ), 2272 ) 2273 fireteams_.append(fireteams_fields) 2274 if no_results: 2275 return fireteams_fields 2276 return fireteams_
Deserialize a JSON payload of a sequence of/fireteam information.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload. - no_results (
bool): Whether to deserialize the data fromresultsin the payload or not.
Returns
typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]# noqa (E501): An available fireteam or a sequence of available fireteam.
2278 def deserialize_fireteam_party( 2279 self, payload: typedefs.JSONObject 2280 ) -> fireteams.FireteamParty: 2281 last_destination_hash: typing.Optional[int] = None 2282 if raw_dest_hash := payload.get("lastOrbitedDestinationHash"): 2283 last_destination_hash = int(raw_dest_hash) 2284 2285 return fireteams.FireteamParty( 2286 members=[ 2287 self._deserialize_fireteam_party_member(member) 2288 for member in payload["partyMembers"] 2289 ], 2290 activity=self._deserialize_fireteam_party_current_activity( 2291 payload["currentActivity"] 2292 ), 2293 settings=self._deserialize_fireteam_party_settings(payload["joinability"]), 2294 last_destination_hash=last_destination_hash, 2295 tracking=payload["tracking"], 2296 )
Deserialize a JSON payload of profileTransitory component response.
Parameters
- payload (
aiobungie.typedefs.JSONObject): The JSON payload.
Returns
aiobungie.crates.FireteamParty: A fireteam party object of the current fireteam.
2343 def deserialize_seasonal_artifact( 2344 self, payload: typedefs.JSONObject 2345 ) -> season.Artifact: 2346 if raw_artifact := payload.get("seasonalArtifact"): 2347 if points := raw_artifact.get("pointProgression"): 2348 points_prog = progressions.Progression( 2349 hash=points["progressionHash"], 2350 level=points["level"], 2351 cap=points["levelCap"], 2352 daily_limit=points["dailyLimit"], 2353 weekly_limit=points["weeklyLimit"], 2354 current_progress=points["currentProgress"], 2355 daily_progress=points["dailyProgress"], 2356 needed=points["progressToNextLevel"], 2357 next_level=points["nextLevelAt"], 2358 ) 2359 2360 if bonus := raw_artifact.get("powerBonusProgression"): 2361 power_bonus_prog = progressions.Progression( 2362 hash=bonus["progressionHash"], 2363 level=bonus["level"], 2364 cap=bonus["levelCap"], 2365 daily_limit=bonus["dailyLimit"], 2366 weekly_limit=bonus["weeklyLimit"], 2367 current_progress=bonus["currentProgress"], 2368 daily_progress=bonus["dailyProgress"], 2369 needed=bonus["progressToNextLevel"], 2370 next_level=bonus["nextLevelAt"], 2371 ) 2372 artifact = season.Artifact( 2373 net=self._net, 2374 hash=raw_artifact["artifactHash"], 2375 power_bonus=raw_artifact["powerBonus"], 2376 acquired_points=raw_artifact["pointsAcquired"], 2377 bonus=power_bonus_prog, 2378 points=points_prog, 2379 ) 2380 return artifact
Deserialize a JSON payload of a Destiny 2 seasonal artifact information.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.Artifact: A seasonal artifact.
2382 def deserialize_profile_progression( 2383 self, payload: typedefs.JSONObject 2384 ) -> profile.ProfileProgression: 2385 return profile.ProfileProgression( 2386 artifact=self.deserialize_seasonal_artifact(payload["data"]), 2387 checklist={ 2388 int(check_id): checklists 2389 for check_id, checklists in payload["data"]["checklists"].items() 2390 }, 2391 )
Deserialize a JSON payload of a profile progression component.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ProfileProgression: A profile progression component.
2393 def deserialize_instanced_item( 2394 self, payload: typedefs.JSONObject 2395 ) -> items.ItemInstance: 2396 damage_type_hash: typing.Optional[int] = None 2397 if raw_damagetype_hash := payload.get("damageTypeHash"): 2398 damage_type_hash = int(raw_damagetype_hash) 2399 2400 required_hashes: typing.Optional[collections.Collection[int]] = None 2401 if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"): 2402 required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes] 2403 2404 breaker_type: typing.Optional[items.ItemBreakerType] = None 2405 if raw_break_type := payload.get("breakerType"): 2406 breaker_type = items.ItemBreakerType(int(raw_break_type)) 2407 2408 breaker_type_hash: typing.Optional[int] = None 2409 if raw_break_type_hash := payload.get("breakerTypeHash"): 2410 breaker_type_hash = int(raw_break_type_hash) 2411 2412 energy: typing.Optional[items.ItemEnergy] = None 2413 if raw_energy := payload.get("energy"): 2414 energy = self.deserialize_item_energy(raw_energy) 2415 2416 primary_stats = None 2417 if raw_primary_stats := payload.get("primaryStat"): 2418 primary_stats = self.deserialize_item_stats_view(raw_primary_stats) 2419 2420 return items.ItemInstance( 2421 damage_type=enums.DamageType(int(payload["damageType"])), 2422 damage_type_hash=damage_type_hash, 2423 primary_stat=primary_stats, 2424 item_level=int(payload["itemLevel"]), 2425 quality=int(payload["quality"]), 2426 is_equipped=payload["isEquipped"], 2427 can_equip=payload["canEquip"], 2428 equip_required_level=int(payload["equipRequiredLevel"]), 2429 required_equip_unlock_hashes=required_hashes, 2430 cant_equip_reason=int(payload["cannotEquipReason"]), 2431 breaker_type=breaker_type, 2432 breaker_type_hash=breaker_type_hash, 2433 energy=energy, 2434 )
Deserialize a JSON object into an instanced item.
Parameters
- payload (
aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
aiobungie.crates.ItemInstance: An instanced item object.
2436 def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy: 2437 energy_hash: typing.Optional[int] = None 2438 if raw_energy_hash := payload.get("energyTypeHash"): 2439 energy_hash = int(raw_energy_hash) 2440 2441 return items.ItemEnergy( 2442 hash=energy_hash, 2443 type=items.ItemEnergyType(int(payload["energyType"])), 2444 capacity=int(payload["energyCapacity"]), 2445 used_energy=int(payload["energyUsed"]), 2446 unused_energy=int(payload["energyUnused"]), 2447 )
2449 def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk: 2450 perk_hash: typing.Optional[int] = None 2451 if raw_perk_hash := payload.get("perkHash"): 2452 perk_hash = int(raw_perk_hash) 2453 2454 return items.ItemPerk( 2455 hash=perk_hash, 2456 icon=assets.Image(payload["iconPath"]), 2457 is_active=payload["isActive"], 2458 is_visible=payload["visible"], 2459 )
2461 def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket: 2462 plug_hash: typing.Optional[int] = None 2463 if raw_plug_hash := payload.get("plugHash"): 2464 plug_hash = int(raw_plug_hash) 2465 2466 enable_fail_indexes: typing.Optional[list[int]] = None 2467 if raw_indexes := payload.get("enableFailIndexes"): 2468 enable_fail_indexes = [int(index) for index in raw_indexes] 2469 2470 return items.ItemSocket( 2471 plug_hash=plug_hash, 2472 is_enabled=payload["isEnabled"], 2473 enable_fail_indexes=enable_fail_indexes, 2474 is_visible=payload.get("visible"), 2475 )
2484 def deserialize_plug_item_state( 2485 self, payload: typedefs.JSONObject 2486 ) -> items.PlugItemState: 2487 item_hash: typing.Optional[int] = None 2488 if raw_item_hash := payload.get("plugItemHash"): 2489 item_hash = int(raw_item_hash) 2490 2491 insert_fail_indexes: typedefs.NoneOr[list[int]] = None 2492 if raw_fail_indexes := payload.get("insertFailIndexes"): 2493 insert_fail_indexes = [int(k) for k in raw_fail_indexes] 2494 2495 enable_fail_indexes: typedefs.NoneOr[list[int]] = None 2496 if raw_enabled_indexes := payload.get("enableFailIndexes"): 2497 enable_fail_indexes = [int(k) for k in raw_enabled_indexes] 2498 2499 return items.PlugItemState( 2500 item_hash=item_hash, 2501 insert_fail_indexes=insert_fail_indexes, 2502 enable_fail_indexes=enable_fail_indexes, 2503 is_enabled=payload["enabled"], 2504 can_insert=payload["canInsert"], 2505 )
68@typing.final 69class FireteamActivity(int, enums.Enum): 70 """An enum for the fireteam activities.""" 71 72 ALL = 0 73 CRUCIBLE = 2 74 TRIALS_OF_OSIRIS = 3 75 NIGHTFALL = 4 76 ANY = 5 77 GAMBIT = 6 78 BLIND_WELL = 7 79 NIGHTMARE_HUNTS = 12 80 ALTARS_OF_SORROWS = 14 81 DUNGEON = 15 82 RAID_LW = 20 83 RAID_GOS = 21 84 RAID_DSC = 22 85 EXO_CHALLENGE = 23 86 S12_WRATHBORN = 24 87 EMPIRE_HUNTS = 25 88 S13_BATTLEGROUNDS = 26 89 EXOTIC_QUEST = 27 90 RAID_VOG = 28 91 S14_EXPUNGE = 30 92 S15_ASTRAL_ALIGNMENT = 31 93 S15_SHATTERED_RELAM = 32 94 SHATTERED_THRONE = 33 95 PROPHECY = 34 96 PIT_OF_HERESY = 35 97 DOE = 36 98 """Dares of Eternity.""" 99 DUNGEON_GOA = 37 100 """Grasp of Avarice.""" 101 VOW_OF_THE_DISCPILE = 38 102 CAMPAIGN = 39 103 WELLSPRING = 40 104 S16_BATTLEGROUNDS = 41 105 S17_NIGHTMARE_CONTAINMENT = 44 106 S17_SEVER = 45
An enum for the fireteam activities.
132@typing.final 133class FireteamDate(int, enums.Enum): 134 """An enum for fireteam date ranges.""" 135 136 ALL = 0 137 NOW = 1 138 TODAY = 2 139 TWO_DAYS = 3 140 THIS_WEEK = 4
An enum for fireteam date ranges.
109@typing.final 110class FireteamLanguage(str, enums.Enum): 111 """An enum for fireteams languages filters.""" 112 113 ALL = "" 114 ENGLISH = "en" 115 FRENCH = "fr" 116 ESPANOL = "es" 117 DEUTSCH = "de" 118 ITALIAN = "it" 119 JAPANESE = "ja" 120 PORTUGUESE = "pt-br" 121 RUSSIAN = "ru" 122 POLISH = "pl" 123 KOREAN = "ko" 124 # ? China 125 ZH_CHT = "zh-cht" 126 ZH_CHS = "zh-chs" 127 128 def __str__(self) -> str: 129 return str(self.value)
An enum for fireteams languages filters.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
55@typing.final 56class FireteamPlatform(int, enums.Enum): 57 """An enum for fireteam related to bungie fireteams. 58 This is different from the normal `aiobungie.MembershipType`. 59 """ 60 61 ANY = 0 62 PSN_NETWORK = 1 63 XBOX_LIVE = 2 64 STEAM = 4 65 STADIA = 5
An enum for fireteam related to bungie fireteams.
This is different from the normal aiobungie.MembershipType.
102class Flag(__enum.Flag): 103 """Builtin Python enum flag with extra handlings.""" 104 105 # Needs to type this here for mypy 106 _value_: int 107 108 @property 109 def name(self) -> str: # type: ignore[override] 110 if self._name_ is None: 111 self._name_ = f"UNKNOWN {self._value_}" 112 113 return self._name_ 114 115 @property 116 def value(self) -> int: # type: ignore[override] 117 return self._value_ 118 119 def __str__(self) -> str: 120 return self.name 121 122 def __repr__(self) -> str: 123 return f"<{type(self).__name__}.{self.name}: {self._value_!s}>" 124 125 def __int__(self) -> int: 126 if isinstance(self.value, _ITERABLE): 127 raise TypeError( 128 f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.", 129 ) 130 return int(self.value) 131 132 def __or__(self, other: typing.Union[Flag, int]) -> Flag: 133 return self.__class__(self._value_ | int(other)) 134 135 def __xor__(self, other: typing.Union[Flag, int]) -> Flag: 136 return self.__class__(self._value_ ^ int(other)) 137 138 def __and__(self, other: typing.Union[Flag, int]) -> Flag: 139 return self.__class__(other & int(other)) 140 141 def __invert__(self) -> Flag: 142 return self.__class__(~self._value_) 143 144 def __contains__(self, other: typing.Union[Flag, int]) -> bool: 145 return self.value & int(other) == int(other)
Builtin Python enum flag with extra handlings.
43class FlatIterator(typing.Generic[Item]): 44 """A Flat, In-Memory iterator for sequenced based data. 45 46 This can either be used sync or asynchronously. 47 48 Example 49 ------- 50 ```py 51 iterator = FlatIterator([1, 2, 3]) 52 53 # Limit the results to 2. 54 async for item in iterator.take(2): 55 print(item) 56 # 1 57 # 2 58 59 # Filter the results. 60 async for item in iterator.filter(lambda item: item > 1): 61 print(item) 62 print(iterator.count()) 63 # 2 64 # 3 65 # 3 66 67 # Map the results. 68 async for item in iterator.map(lambda item: item * 2): 69 print(item) 70 # 2 71 # 4 72 73 # This also works synchronously. 74 iterator = FlatIterator(["Hello", "World", "!"]) 75 for item in iterator.discard(lambda item: "!" in item): 76 print(item) 77 # Hello 78 # World 79 80 # Indexing is also supported. 81 82 print(iterator[0]) 83 # Hello 84 ``` 85 86 Parameters 87 ---------- 88 items: `collections.Iterable[Item]` 89 The items to iterate over. 90 """ 91 92 __slots__ = ("_items",) 93 94 def __init__(self, items: collections.Iterable[Item]) -> None: 95 self._items = iter(items) 96 97 @typing.overload 98 def collect(self) -> list[Item]: 99 ... 100 101 @typing.overload 102 def collect(self, casting: _B) -> list[_B]: 103 """Collects all items in the iterator into a list and cast them into an object if provided. 104 105 Example 106 ------- 107 >>> iterator = FlatIterator([1, 2, 3]) 108 >>> iterator.collect(casting=str) 109 ["1", "2", "3"] 110 111 Parameters 112 ---------- 113 casting: `T | None` 114 The type to cast the items to. If `None` is provided, the items will be returned as is. 115 116 Raises 117 ------ 118 `StopIteration` 119 If no elements are left in the iterator. 120 """ 121 ... 122 123 def collect( 124 self, casting: typing.Optional[_B] = None 125 ) -> typing.Union[list[Item], list[_B]]: 126 """Collects all items in the iterator into a list. 127 128 Example 129 ------- 130 >>> iterator = FlatIterator([1, 2, 3]) 131 >>> iterator.collect() 132 [1, 2, 3] 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 if casting is not None: 140 return typing.cast(list[_B], list(map(casting, self._items))) 141 142 return list(self._items) 143 144 def next(self) -> Item: 145 """Returns the next item in the iterator. 146 147 Example 148 ------- 149 >>> iterator = FlatIterator[str](["1", "2", "3"]) 150 item = iterator.next() 151 assert item == "1" 152 item = iterator.next() 153 assert item == "2" 154 155 Raises 156 ------ 157 `StopIteration` 158 If no elements are left in the iterator. 159 """ 160 try: 161 return self.__next__() 162 except StopIteration: 163 self._ok() 164 165 def map( 166 self, predicate: collections.Callable[[Item], OtherItem] 167 ) -> FlatIterator[OtherItem]: 168 """Maps each item in the iterator to its predicated value. 169 170 Example 171 ------- 172 >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value)) 173 <FlatIterator([1, 2, 3])> 174 >>> async for item in iterator: 175 assert isinstance(item, int) 176 177 Parameters 178 ---------- 179 predicate: `collections.Callable[[Item], Item]` 180 The function to map each item in the iterator to its predicated value. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return FlatIterator(map(predicate, self._items)) 188 189 def take(self, n: int) -> FlatIterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 196 >>> async for mode in iterator.take(2): 197 assert mode in [GameMode.RAID, GameMode.STRIKE] 198 <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 199 200 Parameters 201 ---------- 202 n: `int` 203 The number of items to take. 204 205 Raises 206 ------ 207 `StopIteration` 208 If no elements are left in the iterator. 209 """ 210 return FlatIterator(itertools.islice(self._items, n)) 211 212 def take_while( 213 self, predicate: collections.Callable[[Item], bool] 214 ) -> FlatIterator[Item]: 215 """Yields items from the iterator while predicate returns `True`. 216 217 Example 218 ------- 219 ```py 220 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 221 222 async for platform in ( 223 iterator 224 .take_while(lambda platform: platform is not MembershipType.XBOX) 225 ): 226 print(platform) 227 # <FlatIterator([MembershipType.STEAM])> 228 ``` 229 230 Parameters 231 ---------- 232 predicate: `collections.Callable[[Item], bool]` 233 The function to predicate each item in the iterator. 234 235 Raises 236 ------ 237 `StopIteration` 238 If no elements are left in the iterator. 239 """ 240 return FlatIterator(itertools.takewhile(predicate, self._items)) 241 242 def drop_while( 243 self, predicate: collections.Callable[[Item], bool] 244 ) -> FlatIterator[Item]: 245 """Yields items from the iterator while predicate returns `False`. 246 247 Example 248 ------- 249 ```py 250 iterator = FlatIterator( 251 [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")] 252 ) 253 254 async for membership in ( 255 iterator 256 .drop_while(lambda membership: membership.name is not "Jim") 257 ): 258 print(membership) 259 # <FlatIterator([DestinyMembership(name="Bob")])> 260 ``` 261 262 Parameters 263 ---------- 264 predicate: `collections.Callable[[Item], bool]` 265 The function to predicate each item in the iterator. 266 267 Raises 268 ------ 269 `StopIteration` 270 If no elements are left in the iterator. 271 """ 272 return FlatIterator(itertools.dropwhile(predicate, self._items)) 273 274 def filter( 275 self, predicate: collections.Callable[[Item], bool] 276 ) -> FlatIterator[Item]: 277 """Filters the iterator to only yield items that match the predicate. 278 279 Example 280 ------- 281 ```py 282 activities = FlatIterator( 283 [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)] 284 # Assuming Raid is solo, Strike is flawless. 285 ) 286 287 async for activity in ( 288 activities 289 .filter(lambda activity: activity.is_solo or activity.is_flawless) 290 ): 291 print(member) 292 # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])> 293 ``` 294 """ 295 return FlatIterator(filter(predicate, self._items)) 296 297 def skip(self, n: int) -> FlatIterator[Item]: 298 """Skips the first number of items in the iterator. 299 300 Example 301 ------- 302 ```py 303 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 304 305 async for platform in iterator.skip(1): 306 print(platform) 307 # Skip the first item in the iterator. 308 # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 309 """ 310 return FlatIterator(itertools.islice(self._items, n, None)) 311 312 def discard( 313 self, predicate: collections.Callable[[Item], bool] 314 ) -> FlatIterator[Item]: 315 """Discards all elements in the iterator for which the predicate function returns true. 316 317 Example 318 ------- 319 >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 320 >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM): 321 # Drops all memberships that are not steam. 322 print(iterator) 323 <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return FlatIterator(filter(lambda x: not predicate(x), self._items)) 336 337 def zip( 338 self, other: FlatIterator[OtherItem] 339 ) -> FlatIterator[tuple[Item, OtherItem]]: 340 """Zips the iterator with another iterable. 341 342 Example 343 ------- 344 >>> iterator = FlatIterator([1, 2, 3]) 345 >>> other = FlatIterator([4, 5, 6]) 346 >>> async for item, other_item in iterator.zip(other): 347 assert item == other_item 348 <FlatIterator([(1, 4), (2, 5), (3, 6)])> 349 350 Parameters 351 ---------- 352 other: `FlatIterator[OtherItem]` 353 The iterable to zip with. 354 355 Raises 356 ------ 357 `StopIteration` 358 If no elements are left in the iterator. 359 """ 360 return FlatIterator(zip(self._items, other)) 361 362 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 363 """`True` if all items in the iterator match the predicate. 364 365 Example 366 ------- 367 >>> iterator = FlatIterator([1, 2, 3]) 368 >>> while iterator.all(lambda item: isinstance(item, int)): 369 print("Still all integers") 370 continue 371 # Still all integers 372 373 Parameters 374 ---------- 375 predicate: `collections.Callable[[Item], bool]` 376 The function to test each item in the iterator. 377 378 Raises 379 ------ 380 `StopIteration` 381 If no elements are left in the iterator. 382 """ 383 return all(predicate(item) for item in self) 384 385 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 386 """`True` if any items in the iterator match the predicate. 387 388 Example 389 ------- 390 >>> iterator = FlatIterator([1, 2, 3]) 391 >>> if iterator.any(lambda item: isinstance(item, int)): 392 print("At least one item is an int.") 393 # At least one item is an int. 394 395 Parameters 396 ---------- 397 predicate: `collections.Callable[[Item], bool]` 398 The function to test each item in the iterator. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return any(predicate(item) for item in self) 406 407 def sort( 408 self, 409 *, 410 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 411 reverse: bool = False, 412 ) -> FlatIterator[Item]: 413 """Sorts the iterator. 414 415 Example 416 ------- 417 >>> iterator = FlatIterator([3, 1, 6, 7]) 418 >>> async for item in iterator.sort(key=lambda item: item < 3): 419 print(item) 420 # 1 421 # 3 422 # 6 423 # 7 424 425 Parameters 426 ---------- 427 key: `collections.Callable[[Item], Any]` 428 The function to sort by. 429 reverse: `bool` 430 Whether to reverse the sort. 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return FlatIterator(sorted(self._items, key=key, reverse=reverse)) 438 439 def first(self) -> Item: 440 """Returns the first item in the iterator. 441 442 Example 443 ------- 444 >>> iterator = FlatIterator([3, 1, 6, 7]) 445 >>> iterator.first() 446 3 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return self.take(1).next() 454 455 def reversed(self) -> FlatIterator[Item]: 456 """Returns a new iterator that yields the items in the iterator in reverse order. 457 458 Example 459 ------- 460 >>> iterator = FlatIterator([3, 1, 6, 7]) 461 >>> async for item in iterator.reversed(): 462 print(item) 463 # 7 464 # 6 465 # 1 466 # 3 467 468 Raises 469 ------ 470 `StopIteration` 471 If no elements are left in the iterator. 472 """ 473 return FlatIterator(reversed(self.collect())) 474 475 def count(self) -> int: 476 count = 0 477 for _ in self: 478 count += 1 479 480 return count 481 482 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 483 """Returns a new iterator that yields all items from both iterators. 484 485 Example 486 ------- 487 >>> iterator = FlatIterator([1, 2, 3]) 488 >>> other = FlatIterator([4, 5, 6]) 489 >>> async for item in iterator.union(other): 490 print(item) 491 # 1 492 # 2 493 # 3 494 # 4 495 # 5 496 # 6 497 498 Parameters 499 ---------- 500 other: `FlatIterator[Item]` 501 The iterable to union with. 502 503 Raises 504 ------ 505 `StopIteration` 506 If no elements are left in the iterator. 507 """ 508 return FlatIterator(itertools.chain(self._items, other)) 509 510 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 511 """Calls the function on each item in the iterator. 512 513 Example 514 ------- 515 >>> iterator = FlatIterator([1, 2, 3]) 516 >>> iterator.for_each(lambda item: print(item)) 517 # 1 518 # 2 519 # 3 520 521 Parameters 522 ---------- 523 func: `typeshed.Callable[[Item], None]` 524 The function to call on each item in the iterator. 525 """ 526 for item in self: 527 func(item) 528 529 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 530 """Returns a new iterator that yields tuples of the index and item. 531 532 Example 533 ------- 534 >>> iterator = FlatIterator([1, 2, 3]) 535 >>> async for index, item in iterator.enumerate(): 536 print(index, item) 537 538 # 0, 1 539 # 1, 2 540 # 2, 3 541 542 Raises 543 ------ 544 `StopIteration` 545 If no elements are left in the iterator. 546 """ 547 return FlatIterator(enumerate(self._items, start=start)) 548 549 def _ok(self) -> typing.NoReturn: 550 raise StopIteration("No more items in the iterator.") from None 551 552 def __getitem__(self, index: int) -> Item: 553 try: 554 return self.skip(index).first() 555 except IndexError: 556 self._ok() 557 558 # This is a never. 559 def __setitem__(self) -> typing.NoReturn: 560 raise TypeError( 561 f"{type(self).__name__} doesn't support item assignment." 562 ) from None 563 564 def __repr__(self) -> str: 565 return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>' 566 567 def __len__(self) -> int: 568 return self.count() 569 570 # We support both sync and async iter. 571 def __iter__(self) -> FlatIterator[Item]: 572 return self 573 574 def __aiter__(self) -> FlatIterator[Item]: 575 return self 576 577 def __next__(self) -> Item: 578 try: 579 item = next(self._items) 580 except StopIteration: 581 self._ok() 582 583 return item 584 585 async def __anext__(self) -> Item: 586 try: 587 item = next(self._items) 588 except StopIteration as e: 589 raise StopAsyncIteration from e 590 591 return item
A Flat, In-Memory iterator for sequenced based data.
This can either be used sync or asynchronously.
Example
iterator = FlatIterator([1, 2, 3])
# Limit the results to 2.
async for item in iterator.take(2):
print(item)
# 1
# 2
# Filter the results.
async for item in iterator.filter(lambda item: item > 1):
print(item)
print(iterator.count())
# 2
# 3
# 3
# Map the results.
async for item in iterator.map(lambda item: item * 2):
print(item)
# 2
# 4
# This also works synchronously.
iterator = FlatIterator(["Hello", "World", "!"])
for item in iterator.discard(lambda item: "!" in item):
print(item)
# Hello
# World
# Indexing is also supported.
print(iterator[0])
# Hello
Parameters
- items (
collections.Iterable[Item]): The items to iterate over.
123 def collect( 124 self, casting: typing.Optional[_B] = None 125 ) -> typing.Union[list[Item], list[_B]]: 126 """Collects all items in the iterator into a list. 127 128 Example 129 ------- 130 >>> iterator = FlatIterator([1, 2, 3]) 131 >>> iterator.collect() 132 [1, 2, 3] 133 134 Raises 135 ------ 136 `StopIteration` 137 If no elements are left in the iterator. 138 """ 139 if casting is not None: 140 return typing.cast(list[_B], list(map(casting, self._items))) 141 142 return list(self._items)
Collects all items in the iterator into a list.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect()
[1, 2, 3]
Raises
StopIteration: If no elements are left in the iterator.
144 def next(self) -> Item: 145 """Returns the next item in the iterator. 146 147 Example 148 ------- 149 >>> iterator = FlatIterator[str](["1", "2", "3"]) 150 item = iterator.next() 151 assert item == "1" 152 item = iterator.next() 153 assert item == "2" 154 155 Raises 156 ------ 157 `StopIteration` 158 If no elements are left in the iterator. 159 """ 160 try: 161 return self.__next__() 162 except StopIteration: 163 self._ok()
Returns the next item in the iterator.
Example
>>> iterator = FlatIterator[str](["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
StopIteration: If no elements are left in the iterator.
165 def map( 166 self, predicate: collections.Callable[[Item], OtherItem] 167 ) -> FlatIterator[OtherItem]: 168 """Maps each item in the iterator to its predicated value. 169 170 Example 171 ------- 172 >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value)) 173 <FlatIterator([1, 2, 3])> 174 >>> async for item in iterator: 175 assert isinstance(item, int) 176 177 Parameters 178 ---------- 179 predicate: `collections.Callable[[Item], Item]` 180 The function to map each item in the iterator to its predicated value. 181 182 Raises 183 ------ 184 `StopIteration` 185 If no elements are left in the iterator. 186 """ 187 return FlatIterator(map(predicate, self._items))
Maps each item in the iterator to its predicated value.
Example
>>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
<FlatIterator([1, 2, 3])>
>>> async for item in iterator:
assert isinstance(item, int)
Parameters
- predicate (
collections.Callable[[Item], Item]): The function to map each item in the iterator to its predicated value.
Raises
StopIteration: If no elements are left in the iterator.
189 def take(self, n: int) -> FlatIterator[Item]: 190 """Take the first number of items until the number of items are yielded or 191 the end of the iterator is reached. 192 193 Example 194 ------- 195 >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT]) 196 >>> async for mode in iterator.take(2): 197 assert mode in [GameMode.RAID, GameMode.STRIKE] 198 <FlatIterator([GameMode.RAID, GameMode.STRIKE])> 199 200 Parameters 201 ---------- 202 n: `int` 203 The number of items to take. 204 205 Raises 206 ------ 207 `StopIteration` 208 If no elements are left in the iterator. 209 """ 210 return FlatIterator(itertools.islice(self._items, n))
Take the first number of items until the number of items are yielded or the end of the iterator is reached.
Example
>>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
>>> async for mode in iterator.take(2):
assert mode in [GameMode.RAID, GameMode.STRIKE]
<FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
- n (
int): The number of items to take.
Raises
StopIteration: If no elements are left in the iterator.
212 def take_while( 213 self, predicate: collections.Callable[[Item], bool] 214 ) -> FlatIterator[Item]: 215 """Yields items from the iterator while predicate returns `True`. 216 217 Example 218 ------- 219 ```py 220 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 221 222 async for platform in ( 223 iterator 224 .take_while(lambda platform: platform is not MembershipType.XBOX) 225 ): 226 print(platform) 227 # <FlatIterator([MembershipType.STEAM])> 228 ``` 229 230 Parameters 231 ---------- 232 predicate: `collections.Callable[[Item], bool]` 233 The function to predicate each item in the iterator. 234 235 Raises 236 ------ 237 `StopIteration` 238 If no elements are left in the iterator. 239 """ 240 return FlatIterator(itertools.takewhile(predicate, self._items))
Yields items from the iterator while predicate returns True.
Example
iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
async for platform in (
iterator
.take_while(lambda platform: platform is not MembershipType.XBOX)
):
print(platform)
# <FlatIterator([MembershipType.STEAM])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
242 def drop_while( 243 self, predicate: collections.Callable[[Item], bool] 244 ) -> FlatIterator[Item]: 245 """Yields items from the iterator while predicate returns `False`. 246 247 Example 248 ------- 249 ```py 250 iterator = FlatIterator( 251 [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")] 252 ) 253 254 async for membership in ( 255 iterator 256 .drop_while(lambda membership: membership.name is not "Jim") 257 ): 258 print(membership) 259 # <FlatIterator([DestinyMembership(name="Bob")])> 260 ``` 261 262 Parameters 263 ---------- 264 predicate: `collections.Callable[[Item], bool]` 265 The function to predicate each item in the iterator. 266 267 Raises 268 ------ 269 `StopIteration` 270 If no elements are left in the iterator. 271 """ 272 return FlatIterator(itertools.dropwhile(predicate, self._items))
Yields items from the iterator while predicate returns False.
Example
iterator = FlatIterator(
[DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
)
async for membership in (
iterator
.drop_while(lambda membership: membership.name is not "Jim")
):
print(membership)
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
274 def filter( 275 self, predicate: collections.Callable[[Item], bool] 276 ) -> FlatIterator[Item]: 277 """Filters the iterator to only yield items that match the predicate. 278 279 Example 280 ------- 281 ```py 282 activities = FlatIterator( 283 [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)] 284 # Assuming Raid is solo, Strike is flawless. 285 ) 286 287 async for activity in ( 288 activities 289 .filter(lambda activity: activity.is_solo or activity.is_flawless) 290 ): 291 print(member) 292 # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])> 293 ``` 294 """ 295 return FlatIterator(filter(predicate, self._items))
Filters the iterator to only yield items that match the predicate.
Example
activities = FlatIterator(
[Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
# Assuming Raid is solo, Strike is flawless.
)
async for activity in (
activities
.filter(lambda activity: activity.is_solo or activity.is_flawless)
):
print(member)
# <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
297 def skip(self, n: int) -> FlatIterator[Item]: 298 """Skips the first number of items in the iterator. 299 300 Example 301 ------- 302 ```py 303 iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 304 305 async for platform in iterator.skip(1): 306 print(platform) 307 # Skip the first item in the iterator. 308 # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 309 """ 310 return FlatIterator(itertools.islice(self._items, n, None))
Skips the first number of items in the iterator.
Example
```py iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
async for platform in iterator.skip(1): print(platform)
Skip the first item in the iterator.
MembershipType.XBOX, MembershipType.STADIA])>
312 def discard( 313 self, predicate: collections.Callable[[Item], bool] 314 ) -> FlatIterator[Item]: 315 """Discards all elements in the iterator for which the predicate function returns true. 316 317 Example 318 ------- 319 >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA]) 320 >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM): 321 # Drops all memberships that are not steam. 322 print(iterator) 323 <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])> 324 325 Parameters 326 ---------- 327 predicate: `collections.Callable[[Item], bool]` 328 The function to test each item in the iterator. 329 330 Raises 331 ------ 332 `StopIteration` 333 If no elements are left in the iterator. 334 """ 335 return FlatIterator(filter(lambda x: not predicate(x), self._items))
Discards all elements in the iterator for which the predicate function returns true.
Example
>>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
>>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
# Drops all memberships that are not steam.
print(iterator)
<FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
337 def zip( 338 self, other: FlatIterator[OtherItem] 339 ) -> FlatIterator[tuple[Item, OtherItem]]: 340 """Zips the iterator with another iterable. 341 342 Example 343 ------- 344 >>> iterator = FlatIterator([1, 2, 3]) 345 >>> other = FlatIterator([4, 5, 6]) 346 >>> async for item, other_item in iterator.zip(other): 347 assert item == other_item 348 <FlatIterator([(1, 4), (2, 5), (3, 6)])> 349 350 Parameters 351 ---------- 352 other: `FlatIterator[OtherItem]` 353 The iterable to zip with. 354 355 Raises 356 ------ 357 `StopIteration` 358 If no elements are left in the iterator. 359 """ 360 return FlatIterator(zip(self._items, other))
Zips the iterator with another iterable.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item, other_item in iterator.zip(other):
assert item == other_item
<FlatIterator([(1, 4), (2, 5), (3, 6)])>
Parameters
- other (
FlatIterator[OtherItem]): The iterable to zip with.
Raises
StopIteration: If no elements are left in the iterator.
362 def all(self, predicate: collections.Callable[[Item], bool]) -> bool: 363 """`True` if all items in the iterator match the predicate. 364 365 Example 366 ------- 367 >>> iterator = FlatIterator([1, 2, 3]) 368 >>> while iterator.all(lambda item: isinstance(item, int)): 369 print("Still all integers") 370 continue 371 # Still all integers 372 373 Parameters 374 ---------- 375 predicate: `collections.Callable[[Item], bool]` 376 The function to test each item in the iterator. 377 378 Raises 379 ------ 380 `StopIteration` 381 If no elements are left in the iterator. 382 """ 383 return all(predicate(item) for item in self)
True if all items in the iterator match the predicate.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> while iterator.all(lambda item: isinstance(item, int)):
print("Still all integers")
continue
# Still all integers
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
385 def any(self, predicate: collections.Callable[[Item], bool]) -> bool: 386 """`True` if any items in the iterator match the predicate. 387 388 Example 389 ------- 390 >>> iterator = FlatIterator([1, 2, 3]) 391 >>> if iterator.any(lambda item: isinstance(item, int)): 392 print("At least one item is an int.") 393 # At least one item is an int. 394 395 Parameters 396 ---------- 397 predicate: `collections.Callable[[Item], bool]` 398 The function to test each item in the iterator. 399 400 Raises 401 ------ 402 `StopIteration` 403 If no elements are left in the iterator. 404 """ 405 return any(predicate(item) for item in self)
True if any items in the iterator match the predicate.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> if iterator.any(lambda item: isinstance(item, int)):
print("At least one item is an int.")
<h1 id="at-least-one-item-is-an-int">At least one item is an int.</h1>
Parameters
- predicate (
collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
StopIteration: If no elements are left in the iterator.
407 def sort( 408 self, 409 *, 410 key: collections.Callable[[Item], typeshed.SupportsRichComparison], 411 reverse: bool = False, 412 ) -> FlatIterator[Item]: 413 """Sorts the iterator. 414 415 Example 416 ------- 417 >>> iterator = FlatIterator([3, 1, 6, 7]) 418 >>> async for item in iterator.sort(key=lambda item: item < 3): 419 print(item) 420 # 1 421 # 3 422 # 6 423 # 7 424 425 Parameters 426 ---------- 427 key: `collections.Callable[[Item], Any]` 428 The function to sort by. 429 reverse: `bool` 430 Whether to reverse the sort. 431 432 Raises 433 ------ 434 `StopIteration` 435 If no elements are left in the iterator. 436 """ 437 return FlatIterator(sorted(self._items, key=key, reverse=reverse))
Sorts the iterator.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.sort(key=lambda item: item < 3):
print(item)
<h1 id="1">1</h1>
3
6
7
Parameters
- key (
collections.Callable[[Item], Any]): The function to sort by. - reverse (
bool): Whether to reverse the sort.
Raises
StopIteration: If no elements are left in the iterator.
439 def first(self) -> Item: 440 """Returns the first item in the iterator. 441 442 Example 443 ------- 444 >>> iterator = FlatIterator([3, 1, 6, 7]) 445 >>> iterator.first() 446 3 447 448 Raises 449 ------ 450 `StopIteration` 451 If no elements are left in the iterator. 452 """ 453 return self.take(1).next()
Returns the first item in the iterator.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> iterator.first()
3
Raises
StopIteration: If no elements are left in the iterator.
455 def reversed(self) -> FlatIterator[Item]: 456 """Returns a new iterator that yields the items in the iterator in reverse order. 457 458 Example 459 ------- 460 >>> iterator = FlatIterator([3, 1, 6, 7]) 461 >>> async for item in iterator.reversed(): 462 print(item) 463 # 7 464 # 6 465 # 1 466 # 3 467 468 Raises 469 ------ 470 `StopIteration` 471 If no elements are left in the iterator. 472 """ 473 return FlatIterator(reversed(self.collect()))
Returns a new iterator that yields the items in the iterator in reverse order.
Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.reversed():
print(item)
<h1 id="7">7</h1>
6
1
3
Raises
StopIteration: If no elements are left in the iterator.
482 def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]: 483 """Returns a new iterator that yields all items from both iterators. 484 485 Example 486 ------- 487 >>> iterator = FlatIterator([1, 2, 3]) 488 >>> other = FlatIterator([4, 5, 6]) 489 >>> async for item in iterator.union(other): 490 print(item) 491 # 1 492 # 2 493 # 3 494 # 4 495 # 5 496 # 6 497 498 Parameters 499 ---------- 500 other: `FlatIterator[Item]` 501 The iterable to union with. 502 503 Raises 504 ------ 505 `StopIteration` 506 If no elements are left in the iterator. 507 """ 508 return FlatIterator(itertools.chain(self._items, other))
Returns a new iterator that yields all items from both iterators.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item in iterator.union(other):
print(item)
<h1 id="1">1</h1>
2
3
4
5
6
Parameters
- other (
FlatIterator[Item]): The iterable to union with.
Raises
StopIteration: If no elements are left in the iterator.
510 def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None: 511 """Calls the function on each item in the iterator. 512 513 Example 514 ------- 515 >>> iterator = FlatIterator([1, 2, 3]) 516 >>> iterator.for_each(lambda item: print(item)) 517 # 1 518 # 2 519 # 3 520 521 Parameters 522 ---------- 523 func: `typeshed.Callable[[Item], None]` 524 The function to call on each item in the iterator. 525 """ 526 for item in self: 527 func(item)
Calls the function on each item in the iterator.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.for_each(lambda item: print(item))
<h1 id="1">1</h1>
2
3
Parameters
- func (
typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
529 def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]: 530 """Returns a new iterator that yields tuples of the index and item. 531 532 Example 533 ------- 534 >>> iterator = FlatIterator([1, 2, 3]) 535 >>> async for index, item in iterator.enumerate(): 536 print(index, item) 537 538 # 0, 1 539 # 1, 2 540 # 2, 3 541 542 Raises 543 ------ 544 `StopIteration` 545 If no elements are left in the iterator. 546 """ 547 return FlatIterator(enumerate(self._items, start=start))
Returns a new iterator that yields tuples of the index and item.
Example
>>> iterator = FlatIterator([1, 2, 3])
>>> async for index, item in iterator.enumerate():
print(index, item)
0, 1
1, 2
2, 3
Raises
StopIteration: If no elements are left in the iterator.
133@attrs.define(auto_exc=True) 134class Forbidden(HTTPException): 135 """Exception that's raised for when status code 403 occurs.""" 136 137 http_status: http.HTTPStatus = attrs.field( 138 default=http.HTTPStatus.FORBIDDEN, init=False 139 )
Exception that's raised for when status code 403 occurs.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class Forbidden.
Inherited Members
- builtins.BaseException
- with_traceback
- args
274@typing.final 275class GameMode(int, Enum): 276 """An Enum for all available gamemodes in Destiny 2.""" 277 278 NONE = 0 279 STORY = 2 280 STRIKE = 3 281 RAID = 4 282 ALLPVP = 5 283 PATROL = 6 284 ALLPVE = 7 285 RESERVED9 = 9 286 CONTROL = 10 287 RESERVED11 = 11 288 CLASH = 12 289 RESERVED13 = 13 290 CRIMSONDOUBLES = 15 291 NIGHTFALL = 16 292 HEROICNIGHTFALL = 17 293 ALLSTRIKES = 18 294 IRONBANNER = 19 295 RESERVED20 = 20 296 RESERVED21 = 21 297 RESERVED22 = 22 298 RESERVED24 = 24 299 ALLMAYHEM = 25 300 RESERVED26 = 26 301 RESERVED27 = 27 302 RESERVED28 = 28 303 RESERVED29 = 29 304 RESERVED30 = 30 305 SUPREMACY = 31 306 PRIVATEMATCHESALL = 32 307 SURVIVAL = 37 308 COUNTDOWN = 38 309 TRIALSOFTHENINE = 39 310 SOCIAL = 40 311 TRIALSCOUNTDOWN = 41 312 TRIALSSURVIVAL = 42 313 IRONBANNERCONTROL = 43 314 IRONBANNERCLASH = 44 315 IRONBANNERSUPREMACY = 45 316 SCOREDNIGHTFALL = 46 317 SCOREDHEROICNIGHTFALL = 47 318 RUMBLE = 48 319 ALLDOUBLES = 49 320 DOUBLES = 50 321 PRIVATEMATCHESCLASH = 51 322 PRIVATEMATCHESCONTROL = 52 323 PRIVATEMATCHESSUPREMACY = 53 324 PRIVATEMATCHESCOUNTDOWN = 54 325 PRIVATEMATCHESSURVIVAL = 55 326 PRIVATEMATCHESMAYHEM = 56 327 PRIVATEMATCHESRUMBLE = 57 328 HEROICADVENTURE = 58 329 SHOWDOWN = 59 330 LOCKDOWN = 60 331 SCORCHED = 61 332 SCORCHEDTEAM = 62 333 GAMBIT = 63 334 ALLPVECOMPETITIVE = 64 335 BREAKTHROUGH = 65 336 BLACKARMORYRUN = 66 337 SALVAGE = 67 338 IRONBANNERSALVAGE = 68 339 PVPCOMPETITIVE = 69 340 PVPQUICKPLAY = 70 341 CLASHQUICKPLAY = 71 342 CLASHCOMPETITIVE = 72 343 CONTROLQUICKPLAY = 73 344 CONTROLCOMPETITIVE = 74 345 GAMBITPRIME = 75 346 RECKONING = 76 347 MENAGERIE = 77 348 VEXOFFENSIVE = 78 349 NIGHTMAREHUNT = 79 350 ELIMINATION = 80 351 MOMENTUM = 81 352 DUNGEON = 82 353 SUNDIAL = 83 354 TRIALS_OF_OSIRIS = 84 355 DARES = 85 356 OFFENSIVE = 86 357 LOSTSECTOR = 87 358 RIFT = 88 359 ZONECONTROL = 89 360 IRONBANNERRIFT = 90
An Enum for all available gamemodes in Destiny 2.
58@typing.final 59class GatingScope(int, enums.Enum): 60 """An enum represents restrictive type of gating that is being performed by an entity. 61 62 This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity 63 applies to everyone equally, or to their specific Profile or Character states. 64 """ 65 66 NONE = 0 67 GLOBAL = 1 68 CLAN = 2 69 PROFILE = 3 70 CHARACTER = 4 71 ITEM = 5 72 ASSUMED_WORST_CASE = 6
An enum represents restrictive type of gating that is being performed by an entity.
This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.
487@typing.final 488class Gender(int, Enum): 489 """An Enum for Destiny Genders.""" 490 491 MALE = 0 492 FEMALE = 1 493 UNKNOWN = 2
An Enum for Destiny Genders.
656@typing.final 657class GroupType(int, Enum): 658 """An enums for the known bungie group types.""" 659 660 GENERAL = 0 661 CLAN = 1
An enums for the known bungie group types.
65@attrs.define(auto_exc=True) 66class HTTPError(AiobungieError): 67 """Exception base used for HTTP request errors.""" 68 69 message: str 70 """The error message.""" 71 72 http_status: http.HTTPStatus 73 """The response status."""
Exception base used for HTTP request errors.
2def __init__(self, message, http_status): 3 self.message = message 4 self.http_status = http_status 5 BaseException.__init__(self, self.message,self.http_status)
Method generated by attrs for class HTTPError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
86@attrs.define(auto_exc=True, kw_only=True) 87class HTTPException(HTTPError): 88 """Exception base internally used for an HTTP request response errors.""" 89 90 error_code: int 91 """The returned Bungie error status code.""" 92 93 http_status: http.HTTPStatus 94 """The request response http status.""" 95 96 throttle_seconds: int 97 """The Bungie response throttle seconds.""" 98 99 url: typing.Optional[typedefs.StrOrURL] 100 """The URL/endpoint caused this error.""" 101 102 body: typing.Any 103 """The response body.""" 104 105 headers: multidict.CIMultiDictProxy[str] 106 """The response headers.""" 107 108 message: str 109 """A Bungie human readable message describes the cause of the error.""" 110 111 error_status: str 112 """A Bungie short error status describes the cause of the error.""" 113 114 message_data: dict[str, str] 115 """A dict of string key, value that includes each cause of the error 116 to a message describes information about that error. 117 """ 118 119 def __str__(self) -> str: 120 if self.message: 121 message_body = self.message 122 123 if self.error_status: 124 error_status_body = self.error_status 125 126 return ( 127 f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: " 128 f"Error status: {error_status_body}, Error message: {message_body} from {self.url} " 129 f"{str(self.body)}" 130 )
Exception base internally used for an HTTP request response errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class HTTPException.
A dict of string key, value that includes each cause of the error to a message describes information about that error.
Inherited Members
- builtins.BaseException
- with_traceback
- args
72class Image: 73 """Representation of an image/avatar/picture at Bungie. 74 75 Example 76 ------- 77 ```py 78 from aiobungie import Image 79 img = Image("img/destiny_content/pgcr/raid_eclipse.jpg") 80 print(img) 81 # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg 82 83 # Stream the image. 84 async for chunk in img: 85 # Byte chunks of the image. 86 print(chunk) 87 88 # Save the image to a file. 89 await img.save("file_name", "/my/path/to/save/to", "jpeg") 90 ``` 91 92 Parameters 93 ---------- 94 path : `str | None` 95 The path to the image. If `None`, the default missing image path will be used. 96 """ 97 98 __slots__ = ("_path",) 99 100 def __init__(self, path: typing.Optional[str] = None) -> None: 101 self._path = path 102 103 @property 104 def is_missing(self) -> bool: 105 return not self._path 106 107 @property 108 def url(self) -> str: 109 """The URL to the image.""" 110 return self.create_url() 111 112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png" 116 117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}" 126 127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err 181 182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader 204 205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk 224 225 def __repr__(self) -> str: 226 return f"Image(url={self.create_url()})" 227 228 def __str__(self) -> str: 229 return self.create_url() 230 231 def __aiter__(self) -> Image: 232 return self 233 234 async def __anext__(self) -> bytes: 235 return await self.read() 236 237 def __await__(self) -> collections.Generator[None, None, bytes]: 238 return self.__anext__().__await__()
Representation of an image/avatar/picture at Bungie.
Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
# Stream the image.
async for chunk in img:
# Byte chunks of the image.
print(chunk)
# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
- path (
str | None): The path to the image. IfNone, the default missing image path will be used.
112 @staticmethod 113 def missing_path() -> str: 114 """Returns the path to the missing Bungie image.""" 115 return "img/misc/missing_icon_d2.png"
Returns the path to the missing Bungie image.
117 def create_url(self) -> str: 118 """Creates a full URL to the image path. 119 120 Returns 121 ------- 122 str 123 The URL to the image. 124 """ 125 return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
Creates a full URL to the image path.
Returns
- str: The URL to the image.
127 async def save( 128 self, 129 file_name: str, 130 path: typing.Union[pathlib.Path, str], 131 /, 132 mime_type: typing.Optional[typing.Union[MimeType, str]] = None, 133 ) -> None: 134 """Saves the image to a file. 135 136 Parameters 137 ---------- 138 file_name : `str` 139 A name for the file to save the image to. 140 path : `pathlib.Path | str` 141 A path tp save the image to. 142 143 Other Parameters 144 ---------------- 145 mime_type : `MimeType | str` 146 Optional MIME type of the image. 147 148 Raises 149 ------ 150 `FileNotFoundError` 151 If the path provided does not exist. 152 `RuntimeError` 153 If the image could not be saved. 154 `PermissionError` 155 If the path provided is not writable or does not have write permissions. 156 """ 157 if isinstance(path, pathlib.Path) and not path.exists(): 158 raise FileNotFoundError(f"File does not exist: {path!r}") 159 160 if self.is_missing: 161 return 162 163 mimetype = mime_type or MimeType.PNG 164 path = pathlib.Path(path) 165 166 loop = helpers.get_or_make_loop() 167 pool = concurrent.futures.ThreadPoolExecutor() 168 169 try: 170 with pool: 171 await loop.run_in_executor( 172 pool, _write, path, file_name, mimetype, await self.read() 173 ) 174 _LOGGER.info("Saved image to %s", file_name) 175 176 except asyncio.CancelledError: 177 pass 178 179 except Exception as err: 180 raise RuntimeError("Encountered an error while saving image.") from err
Saves the image to a file.
Parameters
- file_name (
str): A name for the file to save the image to. - path (
pathlib.Path | str): A path tp save the image to.
Other Parameters
- mime_type (
MimeType | str): Optional MIME type of the image.
Raises
FileNotFoundError: If the path provided does not exist.RuntimeError: If the image could not be saved.PermissionError: If the path provided is not writable or does not have write permissions.
182 async def read(self) -> bytes: 183 """Read this image bytes. 184 185 Returns 186 ------- 187 `bytes` 188 The bytes of this image. 189 """ 190 client_session = aiohttp.ClientSession() 191 192 try: 193 await client_session.__aenter__() 194 response = await client_session.get(self.create_url()) 195 196 if 300 >= response.status >= 200: 197 reader = await response.read() 198 199 except Exception as exc: 200 raise RuntimeError(f"Failed to read image: {exc}") from None 201 finally: 202 await client_session.__aexit__(None, None, None) 203 return reader
Read this image bytes.
Returns
bytes: The bytes of this image.
205 async def iter(self) -> collections.AsyncGenerator[bytes, None]: 206 """Iterates over the image bytes lazily. 207 208 Example 209 ------- 210 import aiobungie 211 212 resource = aiobungie.Image("img/misc/missing_icon_d2.png") 213 async for chunk in resource.iter(): 214 print(chunk) 215 216 Returns 217 ------- 218 `collections.AsyncGenerator[bytes, None]` 219 An async generator of the image bytes. 220 """ 221 222 async for chunk in self: 223 yield chunk
Iterates over the image bytes lazily.
Example
import aiobungie
resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)
Returns
collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
203@attrs.define(auto_exc=True) 204class InternalServerError(HTTPException): 205 """Raised for 5xx internal server errors."""
Raised for 5xx internal server errors.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class InternalServerError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
722@typing.final 723class ItemBindStatus(int, Enum): 724 """An enum for Destiny 2 items bind status.""" 725 726 NOT_BOUND = 0 727 BOUND_TO_CHARACTER = 1 728 BOUND_TO_ACCOUNT = 2 729 BOUNT_TO_GUILD = 3
An enum for Destiny 2 items bind status.
732@typing.final 733class ItemLocation(int, Enum): 734 """An enum for Destiny 2 items location.""" 735 736 UNKNOWN = 0 737 INVENTORY = 1 738 VAULT = 2 739 VENDOR = 3 740 POSTMASTER = 4
An enum for Destiny 2 items location.
757@typing.final 758class ItemState(Flag): 759 """An enum for Destiny 2 item states.""" 760 761 NONE = 0 762 LOCKED = 1 763 TRACKED = 2 764 MASTERWORKED = 4 765 CRAFTED = 8 766 """If this bit is set, the item has been 'crafted' by the player.""" 767 HIGHLITED_OBJECTIVE = 16 768 """If this bit is set, the item is a 'highlighted' objective."""
An enum for Destiny 2 item states.
If this bit is set, the item is a 'highlighted' objective.
589@typing.final 590class ItemSubType(int, Enum): 591 """An enum for Destiny 2 inventory items subtype.""" 592 593 NONE = 0 594 AUTORIFLE = 6 595 SHOTGUN = 7 596 MACHINEGUN = 8 597 HANDCANNON = 9 598 ROCKETLAUNCHER = 10 599 FUSIONRIFLE = 11 600 SNIPERRIFLE = 12 601 PULSERIFLE = 13 602 SCOUTRIFLE = 14 603 SIDEARM = 17 604 SWORD = 18 605 MASK = 19 606 SHADER = 20 607 ORNAMENT = 21 608 FUSIONRIFLELINE = 22 609 GRENADELAUNCHER = 23 610 SUBMACHINEGUN = 24 611 TRACERIFLE = 25 612 HELMETARMOR = 26 613 GAUNTLETSARMOR = 27 614 CHESTARMOR = 28 615 LEGARMOR = 29 616 CLASSARMOR = 30 617 BOW = 31 618 DUMMYREPEATABLEBOUNTY = 32
An enum for Destiny 2 inventory items subtype.
621@typing.final 622class ItemTier(int, Enum): 623 """An enum for a Destiny 2 item tier.""" 624 625 NONE = 0 626 BASIC = 3340296461 627 COMMON = 2395677314 628 RARE = 2127292149 629 LEGENDERY = 4008398120 630 EXOTIC = 2759499571
An enum for a Destiny 2 item tier.
556@typing.final 557class ItemType(int, Enum): 558 """Enums for Destiny2's item types.""" 559 560 NONE = 0 561 CURRENCY = 1 562 ARMOR = 2 563 WEAPON = 3 564 MESSAGE = 7 565 ENGRAM = 8 566 CONSUMABLE = 9 567 EXCHANGEMATERIAL = 10 568 MISSIONREWARD = 11 569 QUESTSTEP = 12 570 QUESTSTEPCOMPLETE = 13 571 EMBLEM = 14 572 QUEST = 15 573 SUBCLASS = 16 574 CLANBANNER = 17 575 AURA = 18 576 MOD = 19 577 DUMMY = 20 578 SHIP = 21 579 VEHICLE = 22 580 EMOTE = 23 581 GHOST = 24 582 PACKAGE = 25 583 BOUNTY = 26 584 WRAPPER = 27 585 SEASONALARTIFACT = 28 586 FINISHER = 29
Enums for Destiny2's item types.
713@typing.final 714class MembershipOption(int, Enum): 715 """A enum for GroupV2 membership options.""" 716 717 REVIEWD = 0 718 OPEN = 1 719 CLOSED = 2
A enum for GroupV2 membership options.
463@typing.final 464class MembershipType(int, Enum): 465 """An Enum for Bungie membership types.""" 466 467 NONE = 0 468 XBOX = 1 469 PSN = 2 470 STEAM = 3 471 BLIZZARD = 4 472 STADIA = 5 473 BUNGIE = 254 474 ALL = -1
An Enum for Bungie membership types.
176@attrs.define(auto_exc=True) 177class MembershipTypeError(BadRequest): 178 """A bad request error raised when passing wrong membership to the request. 179 180 Those fields are useful since it returns the correct membership and id which can be used 181 to make the request again with those fields. 182 """ 183 184 membership_type: str = attrs.field(default="") 185 """The errored membership type passed to the request.""" 186 187 membership_id: int = attrs.field(default=0) 188 """The errored user's membership id.""" 189 190 required_membership: str = attrs.field(default="") 191 """The required correct membership for errored user.""" 192 193 def __str__(self) -> str: 194 return ( 195 f"Expected membership: {self.required_membership}, " 196 f"But got {self.membership_type} for id {self.membership_id}" 197 ) 198 199 def __int__(self) -> int: 200 return int(self.membership_id)
A bad request error raised when passing wrong membership to the request.
Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default): 3 self.message = message 4 self.url = url 5 self.body = body 6 self.headers = headers 7 self.http_status = http_status 8 self.membership_type = membership_type 9 self.membership_id = membership_id 10 self.required_membership = required_membership 11 BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)
Method generated by attrs for class MembershipTypeError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
506@typing.final 507class MilestoneType(int, Enum): 508 """An Enum for Destiny 2 milestone types.""" 509 510 UNKNOWN = 0 511 TUTORIAL = 1 512 ONETIME = 2 513 WEEKLY = 3 514 DAILY = 4 515 SPECIAL = 5
An Enum for Destiny 2 milestone types.
142@attrs.define(auto_exc=True) 143class NotFound(HTTPException): 144 """Raised when an unknown request was not found.""" 145 146 http_status: http.HTTPStatus = attrs.field( 147 default=http.HTTPStatus.NOT_FOUND, init=False 148 )
Raised when an unknown request was not found.
2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.throttle_seconds = throttle_seconds 5 self.url = url 6 self.body = body 7 self.headers = headers 8 self.message = message 9 self.error_status = error_status 10 self.message_data = message_data 11 self.http_status = attr_dict['http_status'].default 12 BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class NotFound.
Inherited Members
- builtins.BaseException
- with_traceback
- args
94@typing.final 95class ObjectiveUIStyle(int, enums.Enum): 96 NONE = 0 97 HIGHLIGHTED = 1 98 CRAFTING_WEAPON_LEVEL = 2 99 CRAFTING_WEAPON_LEVEL_PROGRESS = 3 100 CRAFTING_WEAPON_TIMESTAMP = 4 101 CRAFTING_MEMENTOS = 5 102 CRAFTING_MEMENTO_TITLE = 6
An enumeration.
235@typing.final 236class Place(int, Enum): 237 """An Enum for Destiny 2 Places and NOT Planets""" 238 239 ORBIT = 2961497387 240 SOCIAL = 4151112093 241 LIGHT_HOUSE = 4276116472 242 EXPLORE = 3497767639
An Enum for Destiny 2 Places and NOT Planets
200@typing.final 201class Planet(int, Enum): 202 """An Enum for all available planets in Destiny 2.""" 203 204 UNKNOWN = 0 205 """Unknown space""" 206 207 EARTH = 3747705955 208 """Earth""" 209 210 DREAMING_CITY = 2877881518 211 """The Dreaming city.""" 212 213 NESSUS = 3526908984 214 """Nessus""" 215 216 MOON = 3325508439 217 """The Moon""" 218 219 COSMODROME = 3990611421 220 """The Cosmodrome""" 221 222 TANGLED_SHORE = 3821439926 223 """The Tangled Shore""" 224 225 VENUS = 3871070152 226 """Venus""" 227 228 EAZ = 541863059 # Exclusive event. 229 """European Aerial Zone""" 230 231 EUROPA = 1729879943 232 """Europa"""
An Enum for all available planets in Destiny 2.
683@typing.final 684class Presence(int, Enum): 685 """An enum for a bungie friend status.""" 686 687 OFFLINE_OR_UNKNOWN = 0 688 ONLINE = 1
An enum for a bungie friend status.
771@typing.final 772class PrivacySetting(int, Enum): 773 """An enum for players's privacy settings.""" 774 775 OPEN = 0 776 CLAN_AND_FRIENDS = 1 777 FRIENDS_ONLY = 2 778 INVITE_ONLY = 3 779 CLOSED = 4
An enum for players's privacy settings.
350class RESTClient(interfaces.RESTInterface): 351 """A RESTful client implementation for Bungie's API. 352 353 This client is designed to only make HTTP requests and return JSON objects 354 to provide RESTful functionality. 355 356 This client is also used within `aiobungie.Client` which deserialize those returned JSON objects 357 using the factory into Pythonic data classes objects which provide Python functionality. 358 359 Example 360 ------- 361 ```py 362 import aiobungie 363 364 async def main(): 365 async with aiobungie.RESTClient("TOKEN") as rest_client: 366 req = await rest_client.fetch_clan_members(4389205) 367 clan_members = req['results'] 368 for member in clan_members: 369 for k, v in member['destinyUserInfo'].items(): 370 print(k, v) 371 ``` 372 373 Parameters 374 ---------- 375 token : `str` 376 A valid application token from Bungie's developer portal. 377 378 Other Parameters 379 ---------------- 380 max_retries : `int` 381 The max retries number to retry if the request hit a `5xx` status code. 382 max_ratelimit_retries : `int` 383 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 384 client_secret : `typing.Optional[str]` 385 An optional application client secret, 386 This is only needed if you're fetching OAuth2 tokens with this client. 387 client_id : `typing.Optional[int]` 388 An optional application client id, 389 This is only needed if you're fetching OAuth2 tokens with this client. 390 enable_debugging : `bool | str` 391 Whether to enable logging responses or not. 392 393 Logging Levels 394 -------------- 395 * `False`: This will disable logging. 396 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 397 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 398 """ 399 400 __slots__ = ( 401 "_token", 402 "_session", 403 "_lock", 404 "_max_retries", 405 "_client_secret", 406 "_client_id", 407 "_metadata", 408 "_max_rate_limit_retries", 409 ) 410 411 def __init__( 412 self, 413 token: str, 414 /, 415 client_secret: typing.Optional[str] = None, 416 client_id: typing.Optional[int] = None, 417 *, 418 max_retries: int = 4, 419 max_ratelimit_retries: int = 3, 420 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 421 ) -> None: 422 self._session: typing.Optional[_Session] = None 423 self._lock: typing.Optional[asyncio.Lock] = None 424 self._client_secret = client_secret 425 self._client_id = client_id 426 self._token: str = token 427 self._max_retries = max_retries 428 self._max_rate_limit_retries = max_ratelimit_retries 429 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 430 431 self._set_debug_level(enable_debugging) 432 433 @property 434 def client_id(self) -> typing.Optional[int]: 435 return self._client_id 436 437 @property 438 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 439 return self._metadata 440 441 @property 442 def is_alive(self) -> bool: 443 return self._session is not None 444 445 @typing.final 446 async def close(self) -> None: 447 if self._session is not None: 448 await self._session.close() 449 self._session = None 450 451 @typing.final 452 def enable_debugging( 453 self, 454 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 455 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 456 /, 457 ) -> None: 458 self._set_debug_level(level, file) 459 460 @typing.final 461 async def static_request( 462 self, 463 method: typing.Union[RequestMethod, str], 464 path: str, 465 *, 466 auth: typing.Optional[str] = None, 467 json: typing.Optional[dict[str, typing.Any]] = None, 468 ) -> ResponseSig: 469 return await self._request(method, path, auth=auth, json=json) 470 471 @typing.final 472 def build_oauth2_url( 473 self, client_id: typing.Optional[int] = None 474 ) -> typing.Optional[str]: 475 client_id = client_id or self._client_id 476 if client_id is None: 477 return None 478 479 return url.OAUTH2_EP_BUILDER.format( 480 oauth_endpoint=url.OAUTH_EP, 481 client_id=client_id, 482 uuid=_uuid(), 483 ) 484 485 def _open(self) -> _Session: 486 """Open a new client session. This is called internally with contextmanager usage.""" 487 asyncio.get_running_loop() 488 if self._session is None: 489 self._session = _Session.create( 490 owner=False, 491 raise_status=False, 492 connect=None, 493 socket_read=None, 494 socket_connect=None, 495 ) 496 return self._session 497 498 @staticmethod 499 def _set_debug_level( 500 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 501 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 502 ) -> None: 503 504 file_handler = logging.FileHandler(file, mode="w") if file else None 505 if level == "TRACE" or level == TRACE: 506 logging.basicConfig( 507 level=TRACE, handlers=[file_handler] if file_handler else None 508 ) 509 510 elif level: 511 logging.basicConfig( 512 level=logging.DEBUG, handlers=[file_handler] if file_handler else None 513 ) 514 515 async def _request( 516 self, 517 method: typing.Union[RequestMethod, str], 518 route: str, 519 *, 520 base: bool = False, 521 oauth2: bool = False, 522 auth: typing.Optional[str] = None, 523 unwrapping: typing.Literal["json", "read"] = "json", 524 json: typing.Optional[dict[str, typing.Any]] = None, 525 headers: typing.Optional[dict[str, typing.Any]] = None, 526 data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None, 527 ) -> ResponseSig: 528 529 retries: int = 0 530 session = self._open() 531 headers = headers or {} 532 533 headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT) 534 headers["X-API-KEY"] = self._token 535 536 if auth is not None: 537 headers[_AUTH_HEADER] = f"Bearer {auth}" 538 539 # Handling endpoints 540 endpoint = url.BASE 541 542 if not base: 543 endpoint = endpoint + url.REST_EP 544 545 if oauth2: 546 headers["Content-Type"] = "application/x-www-form-urlencoded" 547 endpoint = endpoint + url.TOKEN_EP 548 549 if self._lock is None: 550 self._lock = asyncio.Lock() 551 552 while True: 553 try: 554 async with (stack := contextlib.AsyncExitStack()): 555 await stack.enter_async_context(self._lock) 556 557 # We make the request here. 558 taken_time = time.monotonic() 559 response = await stack.enter_async_context( 560 session.client_session.request( 561 method=method, 562 url=f"{endpoint}/{route}", 563 json=json, 564 headers=headers, 565 data=data, 566 ) 567 ) 568 response_time = (time.monotonic() - taken_time) * 1_000 569 570 _LOG.debug( 571 "%s %s %s Time %.4fms", 572 method, 573 f"{endpoint}/{route}", 574 f"{response.status} {response.reason}", 575 response_time, 576 ) 577 578 await self._handle_ratelimit( 579 response, method, route, self._max_rate_limit_retries 580 ) 581 582 if response.status == http.HTTPStatus.NO_CONTENT: 583 return None 584 585 if 300 > response.status >= 200: 586 if unwrapping == "read": 587 # We need to read the bytes for the manifest response. 588 return await response.read() 589 590 if response.content_type == _APP_JSON: 591 json_data = await response.json() 592 593 _LOG.debug( 594 "%s %s %s Time %.4fms", 595 method, 596 f"{endpoint}/{route}", 597 f"{response.status} {response.reason}", 598 response_time, 599 ) 600 601 if _LOG.isEnabledFor(TRACE): 602 headers.update(response.headers) 603 604 _LOG.log( 605 TRACE, 606 "%s", 607 error.stringify_http_message(headers), 608 ) 609 610 # Return the response. 611 # oauth2 responses are not packed inside a Response object. 612 if oauth2: 613 return json_data # type: ignore[no-any-return] 614 615 return json_data["Response"] # type: ignore[no-any-return] 616 617 if ( 618 response.status in _RETRY_5XX 619 and retries < self._max_retries # noqa: W503 620 ): 621 backoff_ = backoff.ExponentialBackOff(maximum=6) 622 sleep_time = next(backoff_) 623 _LOG.warning( 624 "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i", 625 response.status, 626 response.reason, 627 sleep_time, 628 self._max_retries - retries, 629 ) 630 631 retries += 1 632 await asyncio.sleep(sleep_time) 633 continue 634 635 raise await error.raise_error(response) 636 # eol 637 except _Dyn: 638 continue 639 640 if not typing.TYPE_CHECKING: 641 642 def __enter__(self) -> typing.NoReturn: 643 cls = type(self) 644 raise TypeError( 645 f"{cls.__qualname__} is async only, use 'async with' instead." 646 ) 647 648 def __exit__( 649 self, 650 exception_type: typing.Optional[type[BaseException]], 651 exception: typing.Optional[BaseException], 652 exception_traceback: typing.Optional[types.TracebackType], 653 ) -> None: 654 ... 655 656 async def __aenter__(self) -> RESTClient: 657 self._open() 658 return self 659 660 async def __aexit__( 661 self, 662 exception_type: typing.Optional[type[BaseException]], 663 exception: typing.Optional[BaseException], 664 exception_traceback: typing.Optional[types.TracebackType], 665 ) -> None: 666 await self.close() 667 668 # We don't want this to be super complicated. 669 @staticmethod 670 @typing.final 671 async def _handle_ratelimit( 672 response: aiohttp.ClientResponse, 673 method: str, 674 route: str, 675 max_ratelimit_retries: int = 3, 676 ) -> None: 677 678 if response.status != http.HTTPStatus.TOO_MANY_REQUESTS: 679 return 680 681 if response.content_type != _APP_JSON: 682 raise error.HTTPError( 683 f"Being ratelimited on non JSON request, {response.content_type}.", 684 http.HTTPStatus.TOO_MANY_REQUESTS, 685 ) 686 687 count: int = 0 688 json: typedefs.JSONObject = await response.json() 689 retry_after = float(json["ThrottleSeconds"]) 690 691 while True: 692 if count == max_ratelimit_retries: 693 raise _Dyn 694 695 if retry_after <= 0: 696 # We sleep for a little bit to avoid funky behavior. 697 sleep_time = float(random.random() + 0.93) / 2 698 699 _LOG.warning( 700 "We're being ratelimited with method %s route %s. Sleeping for %.2fs.", 701 method, 702 route, 703 sleep_time, 704 ) 705 count += 1 706 await asyncio.sleep(sleep_time) 707 continue 708 709 raise error.RateLimitedError( 710 body=json, 711 url=str(response.real_url), 712 retry_after=retry_after, 713 ) 714 715 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 716 717 if not isinstance(self._client_id, int): 718 raise TypeError( 719 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 720 ) 721 722 if not isinstance(self._client_secret, str): 723 raise TypeError( 724 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 725 ) 726 727 headers = { 728 "client_secret": self._client_secret, 729 } 730 731 data = ( 732 f"grant_type=authorization_code&code={code}" 733 f"&client_id={self._client_id}&client_secret={self._client_secret}" 734 ) 735 736 response = await self._request( 737 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 738 ) 739 assert isinstance(response, dict) 740 return builders.OAuth2Response.build_response(response) 741 742 async def refresh_access_token( 743 self, refresh_token: str, / 744 ) -> builders.OAuth2Response: 745 if not isinstance(self._client_id, int): 746 raise TypeError( 747 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 748 ) 749 750 if not isinstance(self._client_secret, str): 751 raise TypeError( 752 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 753 ) 754 755 data = { 756 "grant_type": "refresh_token", 757 "refresh_token": refresh_token, 758 "client_id": self._client_id, 759 "client_secret": self._client_secret, 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 763 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 764 assert isinstance(response, dict) 765 return builders.OAuth2Response.build_response(response) 766 767 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 768 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 769 resp = await self._request( 770 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 771 ) 772 assert isinstance(resp, dict) 773 return resp 774 775 async def fetch_user_themes(self) -> typedefs.JSONArray: 776 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 777 resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/") 778 assert isinstance(resp, list) 779 return resp 780 781 async def fetch_membership_from_id( 782 self, 783 id: int, 784 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 785 /, 786 ) -> typedefs.JSONObject: 787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 788 resp = await self._request( 789 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 790 ) 791 assert isinstance(resp, dict) 792 return resp 793 794 async def fetch_player( 795 self, 796 name: str, 797 code: int, 798 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 799 /, 800 ) -> typedefs.JSONArray: 801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 802 resp = await self._request( 803 RequestMethod.POST, 804 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 805 json={"displayName": name, "displayNameCode": code}, 806 ) 807 assert isinstance(resp, list) 808 return resp 809 810 async def search_users(self, name: str, /) -> typedefs.JSONObject: 811 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 812 resp = await self._request( 813 RequestMethod.POST, 814 "User/Search/GlobalName/0", 815 json={"displayNamePrefix": name}, 816 ) 817 assert isinstance(resp, dict) 818 return resp 819 820 async def fetch_clan_from_id( 821 self, id: int, /, access_token: typing.Optional[str] = None 822 ) -> typedefs.JSONObject: 823 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 824 resp = await self._request( 825 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 826 ) 827 assert isinstance(resp, dict) 828 return resp 829 830 async def fetch_clan( 831 self, 832 name: str, 833 /, 834 access_token: typing.Optional[str] = None, 835 *, 836 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 837 ) -> typedefs.JSONObject: 838 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 839 resp = await self._request( 840 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 841 ) 842 assert isinstance(resp, dict) 843 return resp 844 845 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 849 ) 850 assert isinstance(resp, dict) 851 return resp 852 853 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 854 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 855 resp = await self._request( 856 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 857 ) 858 assert isinstance(resp, list) 859 return resp 860 861 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 862 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 863 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 864 assert isinstance(resp, dict) 865 return resp 866 867 async def fetch_character( 868 self, 869 member_id: int, 870 membership_type: typedefs.IntAnd[enums.MembershipType], 871 character_id: int, 872 components: list[enums.ComponentType], 873 auth: typing.Optional[str] = None, 874 ) -> typedefs.JSONObject: 875 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 876 collector = _collect_components(components) 877 response = await self._request( 878 RequestMethod.GET, 879 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 880 f"Character/{character_id}/?components={collector}", 881 auth=auth, 882 ) 883 assert isinstance(response, dict) 884 return response 885 886 async def fetch_activities( 887 self, 888 member_id: int, 889 character_id: int, 890 mode: typedefs.IntAnd[enums.GameMode], 891 membership_type: typedefs.IntAnd[ 892 enums.MembershipType 893 ] = enums.MembershipType.ALL, 894 *, 895 page: int = 0, 896 limit: int = 1, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 resp = await self._request( 900 RequestMethod.GET, 901 f"Destiny2/{int(membership_type)}/Account/" 902 f"{member_id}/Character/{character_id}/Stats/Activities" 903 f"/?mode={int(mode)}&count={limit}&page={page}", 904 ) 905 assert isinstance(resp, dict) 906 return resp 907 908 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 909 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 910 resp = await self._request( 911 RequestMethod.GET, 912 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 913 ) 914 assert isinstance(resp, dict) 915 return resp 916 917 async def fetch_profile( 918 self, 919 membership_id: int, 920 type: typedefs.IntAnd[enums.MembershipType], 921 components: list[enums.ComponentType], 922 auth: typing.Optional[str] = None, 923 ) -> typedefs.JSONObject: 924 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 925 collector = _collect_components(components) 926 response = await self._request( 927 RequestMethod.GET, 928 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 929 auth=auth, 930 ) 931 assert isinstance(response, dict) 932 return response 933 934 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 935 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 936 response = await self._request( 937 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 938 ) 939 assert isinstance(response, dict) 940 return response 941 942 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 943 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 944 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 945 assert isinstance(resp, dict) 946 return resp 947 948 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 949 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 950 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 951 assert isinstance(resp, dict) 952 return resp 953 954 async def fetch_groups_for_member( 955 self, 956 member_id: int, 957 member_type: typedefs.IntAnd[enums.MembershipType], 958 /, 959 *, 960 filter: int = 0, 961 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 962 ) -> typedefs.JSONObject: 963 resp = await self._request( 964 RequestMethod.GET, 965 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 966 ) 967 assert isinstance(resp, dict) 968 return resp 969 970 async def fetch_potential_groups_for_member( 971 self, 972 member_id: int, 973 member_type: typedefs.IntAnd[enums.MembershipType], 974 /, 975 *, 976 filter: int = 0, 977 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 978 ) -> typedefs.JSONObject: 979 resp = await self._request( 980 RequestMethod.GET, 981 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 982 ) 983 assert isinstance(resp, dict) 984 return resp 985 986 async def fetch_clan_members( 987 self, 988 clan_id: int, 989 /, 990 *, 991 name: typing.Optional[str] = None, 992 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 993 ) -> typedefs.JSONObject: 994 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 995 resp = await self._request( 996 RequestMethod.GET, 997 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 998 ) 999 assert isinstance(resp, dict) 1000 return resp 1001 1002 async def fetch_hardlinked_credentials( 1003 self, 1004 credential: int, 1005 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1006 /, 1007 ) -> typedefs.JSONObject: 1008 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1009 resp = await self._request( 1010 RequestMethod.GET, 1011 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1012 ) 1013 assert isinstance(resp, dict) 1014 return resp 1015 1016 async def fetch_user_credentials( 1017 self, access_token: str, membership_id: int, / 1018 ) -> typedefs.JSONArray: 1019 resp = await self._request( 1020 RequestMethod.GET, 1021 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1022 auth=access_token, 1023 ) 1024 assert isinstance(resp, list) 1025 return resp 1026 1027 async def insert_socket_plug( 1028 self, 1029 action_token: str, 1030 /, 1031 instance_id: int, 1032 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1033 character_id: int, 1034 membership_type: typedefs.IntAnd[enums.MembershipType], 1035 ) -> typedefs.JSONObject: 1036 1037 if isinstance(plug, builders.PlugSocketBuilder): 1038 plug = plug.collect() 1039 1040 body = { 1041 "actionToken": action_token, 1042 "itemInstanceId": instance_id, 1043 "plug": plug, 1044 "characterId": character_id, 1045 "membershipType": int(membership_type), 1046 } 1047 resp = await self._request( 1048 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1049 ) 1050 assert isinstance(resp, dict) 1051 return resp 1052 1053 async def insert_socket_plug_free( 1054 self, 1055 access_token: str, 1056 /, 1057 instance_id: int, 1058 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1059 character_id: int, 1060 membership_type: typedefs.IntAnd[enums.MembershipType], 1061 ) -> typedefs.JSONObject: 1062 1063 if isinstance(plug, builders.PlugSocketBuilder): 1064 plug = plug.collect() 1065 1066 body = { 1067 "itemInstanceId": instance_id, 1068 "plug": plug, 1069 "characterId": character_id, 1070 "membershipType": int(membership_type), 1071 } 1072 resp = await self._request( 1073 RequestMethod.POST, 1074 "Destiny2/Actions/Items/InsertSocketPlugFree", 1075 json=body, 1076 auth=access_token, 1077 ) 1078 assert isinstance(resp, dict) 1079 return resp 1080 1081 async def set_item_lock_state( 1082 self, 1083 access_token: str, 1084 state: bool, 1085 /, 1086 item_id: int, 1087 character_id: int, 1088 membership_type: typedefs.IntAnd[enums.MembershipType], 1089 ) -> int: 1090 body = { 1091 "state": state, 1092 "itemId": item_id, 1093 "characterId": character_id, 1094 "membership_type": int(membership_type), 1095 } 1096 response = await self._request( 1097 RequestMethod.POST, 1098 "Destiny2/Actions/Items/SetLockState", 1099 json=body, 1100 auth=access_token, 1101 ) 1102 assert isinstance(response, int) 1103 return response 1104 1105 async def set_quest_track_state( 1106 self, 1107 access_token: str, 1108 state: bool, 1109 /, 1110 item_id: int, 1111 character_id: int, 1112 membership_type: typedefs.IntAnd[enums.MembershipType], 1113 ) -> int: 1114 body = { 1115 "state": state, 1116 "itemId": item_id, 1117 "characterId": character_id, 1118 "membership_type": int(membership_type), 1119 } 1120 response = await self._request( 1121 RequestMethod.POST, 1122 "Destiny2/Actions/Items/SetTrackedState", 1123 json=body, 1124 auth=access_token, 1125 ) 1126 assert isinstance(response, int) 1127 return response 1128 1129 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1130 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1131 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1132 assert isinstance(path, dict) 1133 return path 1134 1135 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1136 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1137 _ensure_manifest_language(language) 1138 1139 content = await self.fetch_manifest_path() 1140 resp = await self._request( 1141 RequestMethod.GET, 1142 content["mobileWorldContentPaths"][language], 1143 unwrapping="read", 1144 base=True, 1145 ) 1146 assert isinstance(resp, bytes) 1147 return resp 1148 1149 async def download_manifest( 1150 self, 1151 language: str = "en", 1152 name: str = "manifest.sqlite3", 1153 *, 1154 force: bool = False, 1155 ) -> None: 1156 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1157 if os.path.exists(name): 1158 1159 if force: 1160 _LOG.debug("Forcing manifest download.") 1161 os.remove(name) 1162 1163 return await self.download_manifest(language, name, force=force) 1164 1165 else: 1166 raise FileExistsError( 1167 "Manifest file already exists, " 1168 "If you want to force download, set the `force` parameter to `True`." 1169 ) 1170 1171 _LOG.debug("Downloading manifest...") 1172 data_bytes = await self.read_manifest_bytes(language) 1173 await asyncio.get_running_loop().run_in_executor( 1174 None, _write_sqlite_bytes, data_bytes, name 1175 ) 1176 1177 async def download_json_manifest(self, language: str = "en") -> None: 1178 _ensure_manifest_language(language) 1179 1180 _LOG.debug("Downloading manifest JSON...") 1181 1182 content = await self.fetch_manifest_path() 1183 json_bytes = await self._request( 1184 RequestMethod.GET, 1185 content["jsonWorldContentPaths"][language], 1186 unwrapping="read", 1187 base=True, 1188 ) 1189 1190 await asyncio.get_running_loop().run_in_executor( 1191 None, _write_json_bytes, json_bytes 1192 ) 1193 _LOG.debug("Finished downloading manifest JSON.") 1194 1195 async def fetch_manifest_version(self) -> str: 1196 return typing.cast(str, (await self.fetch_manifest_path())["version"]) 1197 1198 @staticmethod 1199 @helpers.deprecated( 1200 since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect" 1201 ) 1202 def connect_manifest( 1203 path: typing.Optional[pathlib.Path] = None, 1204 connection: type[sqlite3.Connection] = sqlite3.Connection, 1205 ) -> sqlite3.Connection: 1206 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1207 path = path or pathlib.Path("./manifest.sqlite3") 1208 if not path.exists(): 1209 raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.") 1210 return connection(path.name) 1211 1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp 1227 1228 async def fetch_clan_banners(self) -> typedefs.JSONObject: 1229 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1230 resp = await self._request( 1231 RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/" 1232 ) 1233 assert isinstance(resp, dict) 1234 return resp 1235 1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp 1241 1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp 1251 1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp 1263 1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 ) 1285 1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 ) 1306 1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 ) 1326 1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 ) 1341 1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp 1358 1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 ) 1411 1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 ) 1441 1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp 1451 1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp 1461 1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 ) 1469 1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 ) 1477 1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 ) 1487 1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 ) 1495 1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 ) 1503 1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.Undefined, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 ) 1518 1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.Undefined, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 ) 1534 1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.Undefined, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 ) 1552 1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.Undefined, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 ) 1576 1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 ) 1604 1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 ) 1632 1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp 1656 1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp 1681 1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp 1693 1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp 1715 1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp 1727 1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp 1735 1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp 1747 1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp 1761 1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp 1777 1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp 1785 1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp 1793 1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp 1799 1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp 1805 1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp 1815 1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp 1841 1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp 1853 1854 async def awa_provide_authorization_result( 1855 self, 1856 access_token: str, 1857 selection: int, 1858 correlation_id: str, 1859 nonce: collections.MutableSequence[typing.Union[str, bytes]], 1860 ) -> int: 1861 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1862 1863 body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce} 1864 1865 resp = await self._request( 1866 RequestMethod.POST, 1867 "Destiny2/Awa/AwaProvideAuthorizationResult", 1868 json=body, 1869 auth=access_token, 1870 ) 1871 assert isinstance(resp, int) 1872 return resp 1873 1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp 1901 1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp 1924 1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp 1943 1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp 1948 1949 async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject: 1950 resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/") 1951 assert isinstance(resp, dict) 1952 return resp 1953 1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp 1964 1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp 1975 1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.Undefined, 1985 source: undefined.UndefinedOr[str] = undefined.Undefined, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.Undefined: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.Undefined: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp 2008 2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.Undefined, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.Undefined else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp 2026 2027 async def search_help_articles( 2028 self, text: str, size: str, / 2029 ) -> typedefs.JSONObject: 2030 resp = await self._request( 2031 RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/" 2032 ) 2033 assert isinstance(resp, dict) 2034 return resp 2035 2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.Undefined, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.Undefined: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.Undefined: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.Undefined else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp 2068 2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.Undefined, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.Undefined: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp 2093 2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp 2113 2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp 2132 2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp 2143 2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp 2154 2155 async def fetch_topic_for_content(self, content_id: int, /) -> int: 2156 resp = await self._request( 2157 RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/" 2158 ) 2159 assert isinstance(resp, int) 2160 return resp 2161 2162 async def fetch_forum_tag_suggestions( 2163 self, partial_tag: str, / 2164 ) -> typedefs.JSONObject: 2165 resp = await self._request( 2166 RequestMethod.GET, 2167 "Forum/GetForumTagSuggestions/", 2168 json={"partialtag": partial_tag}, 2169 ) 2170 assert isinstance(resp, dict) 2171 return resp 2172 2173 async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject: 2174 resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/") 2175 assert isinstance(resp, dict) 2176 return resp 2177 2178 async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray: 2179 resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/") 2180 assert isinstance(resp, list) 2181 return resp 2182 2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp 2198 2199 async def fetch_available_avatars(self) -> collections.Mapping[str, int]: 2200 resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/") 2201 assert isinstance(resp, dict) 2202 return resp 2203 2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp 2217 2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp 2228 2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp 2239 2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp 2250 2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.Undefined, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp 2269 2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp 2285 2286 async def fetch_historical_definition(self) -> typedefs.JSONObject: 2287 resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/") 2288 assert isinstance(resp, dict) 2289 return resp 2290 2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp 2318 2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp 2332 2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
A RESTful client implementation for Bungie's API.
This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.
This client is also used within aiobungie.Client which deserialize those returned JSON objects
using the factory into Pythonic data classes objects which provide Python functionality.
Example
import aiobungie
async def main():
async with aiobungie.RESTClient("TOKEN") as rest_client:
req = await rest_client.fetch_clan_members(4389205)
clan_members = req['results']
for member in clan_members:
for k, v in member['destinyUserInfo'].items():
print(k, v)
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
411 def __init__( 412 self, 413 token: str, 414 /, 415 client_secret: typing.Optional[str] = None, 416 client_id: typing.Optional[int] = None, 417 *, 418 max_retries: int = 4, 419 max_ratelimit_retries: int = 3, 420 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 421 ) -> None: 422 self._session: typing.Optional[_Session] = None 423 self._lock: typing.Optional[asyncio.Lock] = None 424 self._client_secret = client_secret 425 self._client_id = client_id 426 self._token: str = token 427 self._max_retries = max_retries 428 self._max_rate_limit_retries = max_ratelimit_retries 429 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 430 431 self._set_debug_level(enable_debugging)
A mutable mapping storage for the user's needs.
This mapping is useful for storing any kind of data that the user may need.
Example
import aiobungie
client = aiobungie.RESTClient(…)
async with client:
# Fetch auth tokens and store them
client.metadata["tokens"] = await client.fetch_access_token("code")
# Some other time.
async with client:
# Retrieve the tokens
tokens: aiobungie.OAuth2Response = client.metadata["tokens"]
# Use them to fetch your user.
user = await client.fetch_current_user_memberships(tokens.access_token)
445 @typing.final 446 async def close(self) -> None: 447 if self._session is not None: 448 await self._session.close() 449 self._session = None
Close this REST client session if it was acquired.
451 @typing.final 452 def enable_debugging( 453 self, 454 level: typing.Union[typing.Literal["TRACE"], bool, int] = False, 455 file: typing.Optional[typing.Union[pathlib.Path, str]] = None, 456 /, 457 ) -> None: 458 self._set_debug_level(level, file)
Enables debugging for the REST calls.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information."TRACE"|aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
- level (
str | bool | int): The level of debugging to enable. - file (
pathlib.Path | str | None): The file path to write the debug logs to. If provided.
460 @typing.final 461 async def static_request( 462 self, 463 method: typing.Union[RequestMethod, str], 464 path: str, 465 *, 466 auth: typing.Optional[str] = None, 467 json: typing.Optional[dict[str, typing.Any]] = None, 468 ) -> ResponseSig: 469 return await self._request(method, path, auth=auth, json=json)
Perform an HTTP request given a valid Bungie endpoint.
Parameters
- method (
aiobungie.RequestMethod | str): The request method, This may beGET,POST,PUT, etc. - path (
str): The Bungie endpoint or path. A path must look something like thisDestiny2/3/Profile/46111239123/... - auth (
str | None): An optional bearer token for methods that requires OAuth2 Authorization header. - json (
dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
aiobungie.rest.ResponseSig: The response payload.
471 @typing.final 472 def build_oauth2_url( 473 self, client_id: typing.Optional[int] = None 474 ) -> typing.Optional[str]: 475 client_id = client_id or self._client_id 476 if client_id is None: 477 return None 478 479 return url.OAUTH2_EP_BUILDER.format( 480 oauth_endpoint=url.OAUTH_EP, 481 client_id=client_id, 482 uuid=_uuid(), 483 )
Builds an OAuth2 URL using the provided user REST/Base client secret/id.
Parameters
- client_id (
int | None): An optional client id to provide, If leftNoneit will roll back to the id passed to theRESTClient, If both isNonethis method will returnNone.
Returns
str | None: If the client id was provided as a parameter or provided inaiobungie.RESTClient, A complete URL will be returned. OtherwiseNonewill be returned.
715 async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response: 716 717 if not isinstance(self._client_id, int): 718 raise TypeError( 719 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 720 ) 721 722 if not isinstance(self._client_secret, str): 723 raise TypeError( 724 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 725 ) 726 727 headers = { 728 "client_secret": self._client_secret, 729 } 730 731 data = ( 732 f"grant_type=authorization_code&code={code}" 733 f"&client_id={self._client_id}&client_secret={self._client_secret}" 734 ) 735 736 response = await self._request( 737 RequestMethod.POST, "", headers=headers, data=data, oauth2=True 738 ) 739 assert isinstance(response, dict) 740 return builders.OAuth2Response.build_response(response)
Makes a POST request and fetch the OAuth2 access_token and refresh token.
Parameters
- code (
str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
Raises
aiobungie.Unauthorized: The passed code was invalid.
742 async def refresh_access_token( 743 self, refresh_token: str, / 744 ) -> builders.OAuth2Response: 745 if not isinstance(self._client_id, int): 746 raise TypeError( 747 f"Expected (int) for client id but got {type(self._client_id).__qualname__}" # type: ignore 748 ) 749 750 if not isinstance(self._client_secret, str): 751 raise TypeError( 752 f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}" # type: ignore 753 ) 754 755 data = { 756 "grant_type": "refresh_token", 757 "refresh_token": refresh_token, 758 "client_id": self._client_id, 759 "client_secret": self._client_secret, 760 "Content-Type": "application/x-www-form-urlencoded", 761 } 762 763 response = await self._request(RequestMethod.POST, "", data=data, oauth2=True) 764 assert isinstance(response, dict) 765 return builders.OAuth2Response.build_response(response)
Refresh OAuth2 access token given its refresh token.
Parameters
- refresh_token (
str): The refresh token.
Returns
aiobungie.builders.OAuth2Response: An OAuth2 deserialized response.
767 async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject: 768 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 769 resp = await self._request( 770 RequestMethod.GET, f"User/GetBungieNetUserById/{id}/" 771 ) 772 assert isinstance(resp, dict) 773 return resp
Fetch a Bungie user by their id.
Parameters
- id (
int): The user id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of users objects.
Raises
aiobungie.NotFound: The user was not found.
781 async def fetch_membership_from_id( 782 self, 783 id: int, 784 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 785 /, 786 ) -> typedefs.JSONObject: 787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 788 resp = await self._request( 789 RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}" 790 ) 791 assert isinstance(resp, dict) 792 return resp
Fetch Bungie user's memberships from their id.
Parameters
- id (
int): The user's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user.
Raises
- aiobungie.NotFound: The requested user was not found.
794 async def fetch_player( 795 self, 796 name: str, 797 code: int, 798 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL, 799 /, 800 ) -> typedefs.JSONArray: 801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 802 resp = await self._request( 803 RequestMethod.POST, 804 f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}", 805 json={"displayName": name, "displayNameCode": code}, 806 ) 807 assert isinstance(resp, list) 808 return resp
Fetch a Destiny 2 Player.
Parameters
- name (
str): The unique Bungie player name. - code (
int): The unique Bungie display name code. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
aiobungie.typedefs.JSONArray: A JSON array of the found player's memberships.
Raises
aiobungie.NotFound: The player was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
810 async def search_users(self, name: str, /) -> typedefs.JSONObject: 811 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 812 resp = await self._request( 813 RequestMethod.POST, 814 "User/Search/GlobalName/0", 815 json={"displayNamePrefix": name}, 816 ) 817 assert isinstance(resp, dict) 818 return resp
Search for users by their global name and return all users who share this name.
Parameters
- name (
str): The user name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the found users.
Raises
aiobungie.NotFound: The user(s) was not found.
820 async def fetch_clan_from_id( 821 self, id: int, /, access_token: typing.Optional[str] = None 822 ) -> typedefs.JSONObject: 823 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 824 resp = await self._request( 825 RequestMethod.GET, f"GroupV2/{id}", auth=access_token 826 ) 827 assert isinstance(resp, dict) 828 return resp
Fetch a Bungie Clan by its id.
Parameters
- id (
int): The clan id.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
830 async def fetch_clan( 831 self, 832 name: str, 833 /, 834 access_token: typing.Optional[str] = None, 835 *, 836 type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 837 ) -> typedefs.JSONObject: 838 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 839 resp = await self._request( 840 RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token 841 ) 842 assert isinstance(resp, dict) 843 return resp
Fetch a Clan by its name. This method will return the first clan found with given name name.
Parameters
- name (
str): The clan name.
Other Parameters
access_token (
typing.Optional[str]): An optional access token to make the request with.If the token was bound to a member of the clan, This field
aiobungie.crates.Clan.current_user_membershipwill be available and will return the membership of the user who made this request.- type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group type, Default is one.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan.
Raises
aiobungie.NotFound: The clan was not found.
845 async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject: 846 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 847 resp = await self._request( 848 RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/" 849 ) 850 assert isinstance(resp, dict) 851 return resp
Fetch the admins and founder members of the clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the clan admins and founder members.
Raises
aiobungie.NotFound: The clan was not found.
853 async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray: 854 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 855 resp = await self._request( 856 RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/" 857 ) 858 assert isinstance(resp, list) 859 return resp
Fetch a clan's conversations.
Parameters
- clan_id (
int): The clan's id.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the conversations.
861 async def fetch_application(self, appid: int, /) -> typedefs.JSONObject: 862 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 863 resp = await self._request(RequestMethod.GET, f"App/Application/{appid}") 864 assert isinstance(resp, dict) 865 return resp
Fetch a Bungie Application.
Parameters
- appid (
int): The application id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application.
867 async def fetch_character( 868 self, 869 member_id: int, 870 membership_type: typedefs.IntAnd[enums.MembershipType], 871 character_id: int, 872 components: list[enums.ComponentType], 873 auth: typing.Optional[str] = None, 874 ) -> typedefs.JSONObject: 875 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 876 collector = _collect_components(components) 877 response = await self._request( 878 RequestMethod.GET, 879 f"Destiny2/{int(membership_type)}/Profile/{member_id}/" 880 f"Character/{character_id}/?components={collector}", 881 auth=auth, 882 ) 883 assert isinstance(response, dict) 884 return response
Fetch a Destiny 2 player's characters.
Parameters
- member_id (
int): A valid bungie member id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type. - character_id (
int): The character id to return. - components (
list[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the requested character.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
886 async def fetch_activities( 887 self, 888 member_id: int, 889 character_id: int, 890 mode: typedefs.IntAnd[enums.GameMode], 891 membership_type: typedefs.IntAnd[ 892 enums.MembershipType 893 ] = enums.MembershipType.ALL, 894 *, 895 page: int = 0, 896 limit: int = 1, 897 ) -> typedefs.JSONObject: 898 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 899 resp = await self._request( 900 RequestMethod.GET, 901 f"Destiny2/{int(membership_type)}/Account/" 902 f"{member_id}/Character/{character_id}/Stats/Activities" 903 f"/?mode={int(mode)}&count={limit}&page={page}", 904 ) 905 assert isinstance(resp, dict) 906 return resp
Fetch a Destiny 2 activity for the specified user id and character.
Parameters
- member_id (
int): The user id that starts with4611. - character_id (
int): The id of the character to retrieve. - mode (
aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
- membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Member ship type, if nothing was passed than it will return all. - page (
int): The page number. Default to1 - limit (
int): Limit the returned result. Default to1
Returns
aiobungie.typedefs.JSONObject: A JSON object of the player's activities.
Raises
aiobungie.NotFound: The activity was not found.aiobungie.MembershipTypeError: The provided membership type was invalid.
908 async def fetch_vendor_sales(self) -> typedefs.JSONObject: 909 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 910 resp = await self._request( 911 RequestMethod.GET, 912 f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}", 913 ) 914 assert isinstance(resp, dict) 915 return resp
917 async def fetch_profile( 918 self, 919 membership_id: int, 920 type: typedefs.IntAnd[enums.MembershipType], 921 components: list[enums.ComponentType], 922 auth: typing.Optional[str] = None, 923 ) -> typedefs.JSONObject: 924 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 925 collector = _collect_components(components) 926 response = await self._request( 927 RequestMethod.GET, 928 f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}", 929 auth=auth, 930 ) 931 assert isinstance(response, dict) 932 return response
Fetch a bungie profile.
Parameters
- membership_id (
int): The member's id. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): A valid membership type. - components (
list[aiobungie.ComponentType]): A list of profile components to collect and return.
Other Parameters
- auth (
typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found profile.
Raises
aiobungie.MembershipTypeError: The provided membership type was invalid.
934 async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject: 935 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 936 response = await self._request( 937 RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}" 938 ) 939 assert isinstance(response, dict) 940 return response
Fetch a Destiny definition item given its type and hash.
Parameters
- type (
str): Entity's type definition. - hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the definition data.
942 async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject: 943 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 944 resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash) 945 assert isinstance(resp, dict) 946 return resp
Fetch a Destiny inventory item entity given a its hash.
Parameters
- hash (
int): Entity's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the inventory item.
948 async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject: 949 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 950 resp = await self.fetch_entity("DestinyObjectiveDefinition", hash) 951 assert isinstance(resp, dict) 952 return resp
Fetch a Destiny objective entity given a its hash.
Parameters
- hash (
int): objective's hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the objetive data.
954 async def fetch_groups_for_member( 955 self, 956 member_id: int, 957 member_type: typedefs.IntAnd[enums.MembershipType], 958 /, 959 *, 960 filter: int = 0, 961 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 962 ) -> typedefs.JSONObject: 963 resp = await self._request( 964 RequestMethod.GET, 965 f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 966 ) 967 assert isinstance(resp, dict) 968 return resp
Fetch the information about the groups for a member.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
970 async def fetch_potential_groups_for_member( 971 self, 972 member_id: int, 973 member_type: typedefs.IntAnd[enums.MembershipType], 974 /, 975 *, 976 filter: int = 0, 977 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 978 ) -> typedefs.JSONObject: 979 resp = await self._request( 980 RequestMethod.GET, 981 f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/", 982 ) 983 assert isinstance(resp, dict) 984 return resp
Get information about the groups that a given member has applied to or been invited to.
Parameters
- member_id (
int): The member's id - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- filter (
builsins.int): Filter apply to list of joined groups. This Default to0 - group_type (
aiobungie.typedefs.IntAnd[aiobungie.GroupType]): The group's type. This is always set toaiobungie.GroupType.CLANand should not be changed.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the member's membership data and groups data.
986 async def fetch_clan_members( 987 self, 988 clan_id: int, 989 /, 990 *, 991 name: typing.Optional[str] = None, 992 type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE, 993 ) -> typedefs.JSONObject: 994 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 995 resp = await self._request( 996 RequestMethod.GET, 997 f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}¤tpage=1", 998 ) 999 assert isinstance(resp, dict) 1000 return resp
Fetch all Bungie Clan members.
Parameters
- clan_id (
builsins.int): The clans id
Other Parameters
- name (
typing.Optional[str]): If provided, Only players matching this name will be returned. - type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): An optional clan member's membership type. Default is set toaiobungie.MembershipType.NONEWhich returns the first matched clan member by their name.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of clan members.
Raises
aiobungie.NotFound: The clan was not found.
1002 async def fetch_hardlinked_credentials( 1003 self, 1004 credential: int, 1005 type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID, 1006 /, 1007 ) -> typedefs.JSONObject: 1008 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1009 resp = await self._request( 1010 RequestMethod.GET, 1011 f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/", 1012 ) 1013 assert isinstance(resp, dict) 1014 return resp
Gets any hard linked membership given a credential.
Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now.
Cross Save aware.
Parameters
- credential (
int): A valid SteamID64 - type (
aiobungie.typedefs.IntAnd[aiobungie.CredentialType]): The crededntial type. This must not be changed Since its only credential that works "currently"
Returns
aiobungie.typedefs.JSONObject: A JSON object of the found user hard linked types.
1016 async def fetch_user_credentials( 1017 self, access_token: str, membership_id: int, / 1018 ) -> typedefs.JSONArray: 1019 resp = await self._request( 1020 RequestMethod.GET, 1021 f"User/GetCredentialTypesForTargetAccount/{membership_id}", 1022 auth=access_token, 1023 ) 1024 assert isinstance(resp, list) 1025 return resp
Fetch an array of credential types attached to the requested account.
This method require OAuth2 Bearer access token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - membership_id (
int): The id of the membership to return.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the returned credentials.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1027 async def insert_socket_plug( 1028 self, 1029 action_token: str, 1030 /, 1031 instance_id: int, 1032 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1033 character_id: int, 1034 membership_type: typedefs.IntAnd[enums.MembershipType], 1035 ) -> typedefs.JSONObject: 1036 1037 if isinstance(plug, builders.PlugSocketBuilder): 1038 plug = plug.collect() 1039 1040 body = { 1041 "actionToken": action_token, 1042 "itemInstanceId": instance_id, 1043 "plug": plug, 1044 "characterId": character_id, 1045 "membershipType": int(membership_type), 1046 } 1047 resp = await self._request( 1048 RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body 1049 ) 1050 assert isinstance(resp, dict) 1051 return resp
Insert a plug into a socketed item.
OAuth2: AdvancedWriteActions scope is required
Parameters
- action_token (
str): Action token provided by the AwaGetActionToken API call. - instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1053 async def insert_socket_plug_free( 1054 self, 1055 access_token: str, 1056 /, 1057 instance_id: int, 1058 plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]], 1059 character_id: int, 1060 membership_type: typedefs.IntAnd[enums.MembershipType], 1061 ) -> typedefs.JSONObject: 1062 1063 if isinstance(plug, builders.PlugSocketBuilder): 1064 plug = plug.collect() 1065 1066 body = { 1067 "itemInstanceId": instance_id, 1068 "plug": plug, 1069 "characterId": character_id, 1070 "membershipType": int(membership_type), 1071 } 1072 resp = await self._request( 1073 RequestMethod.POST, 1074 "Destiny2/Actions/Items/InsertSocketPlugFree", 1075 json=body, 1076 auth=access_token, 1077 ) 1078 assert isinstance(resp, dict) 1079 return resp
Insert a plug into a socketed item. This doesn't require an Action token.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- instance_id (
int): The item instance id that's plug inserted. - plug (
typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
aiobungie.PlugSocketBuilder()
.set_socket_array(0)
.set_socket_index(0)
.set_plug_item(3023847)
.collect()
)
await insert_socket_plug_free(..., plug=plug)
character_id : int
The character's id.
membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType]
The membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains the changed item details.
Raises
aiobungie.Unauthorized: The access token was wrong or no access token passed.
1081 async def set_item_lock_state( 1082 self, 1083 access_token: str, 1084 state: bool, 1085 /, 1086 item_id: int, 1087 character_id: int, 1088 membership_type: typedefs.IntAnd[enums.MembershipType], 1089 ) -> int: 1090 body = { 1091 "state": state, 1092 "itemId": item_id, 1093 "characterId": character_id, 1094 "membership_type": int(membership_type), 1095 } 1096 response = await self._request( 1097 RequestMethod.POST, 1098 "Destiny2/Actions/Items/SetLockState", 1099 json=body, 1100 auth=access_token, 1101 ) 1102 assert isinstance(response, int) 1103 return response
Set the Lock State for an instanced item.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1105 async def set_quest_track_state( 1106 self, 1107 access_token: str, 1108 state: bool, 1109 /, 1110 item_id: int, 1111 character_id: int, 1112 membership_type: typedefs.IntAnd[enums.MembershipType], 1113 ) -> int: 1114 body = { 1115 "state": state, 1116 "itemId": item_id, 1117 "characterId": character_id, 1118 "membership_type": int(membership_type), 1119 } 1120 response = await self._request( 1121 RequestMethod.POST, 1122 "Destiny2/Actions/Items/SetTrackedState", 1123 json=body, 1124 auth=access_token, 1125 ) 1126 assert isinstance(response, int) 1127 return response
Set the Tracking State for an instanced Quest or Bounty.
OAuth2: MoveEquipDestinyItems scope is required
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - state (
bool): IfTrue, The item will be locked, IfFalse, The item will be unlocked. - item_id (
int): The item id. - character_id (
int): The character id. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
int: An integer represents whether the request was successful or failed.
Raises
aiobungie.Unauthorized: - The access token was wrong- No access token passed.
- Other authorization causes.
1129 async def fetch_manifest_path(self) -> typedefs.JSONObject: 1130 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1131 path = await self._request(RequestMethod.GET, "Destiny2/Manifest") 1132 assert isinstance(path, dict) 1133 return path
Fetch the manifest JSON paths.
Returns
typedefs.JSONObject: The manifest JSON paths.
1135 async def read_manifest_bytes(self, language: str = "en", /) -> bytes: 1136 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1137 _ensure_manifest_language(language) 1138 1139 content = await self.fetch_manifest_path() 1140 resp = await self._request( 1141 RequestMethod.GET, 1142 content["mobileWorldContentPaths"][language], 1143 unwrapping="read", 1144 base=True, 1145 ) 1146 assert isinstance(resp, bytes) 1147 return resp
Read raw manifest SQLite database bytes response.
This method can be used to write the bytes to zipped file and then extract it to get the manifest content.
Parameters
- language (
str): The manifest database language bytes to get.
Returns
bytes: The bytes to read and write the manifest database.
1149 async def download_manifest( 1150 self, 1151 language: str = "en", 1152 name: str = "manifest.sqlite3", 1153 *, 1154 force: bool = False, 1155 ) -> None: 1156 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1157 if os.path.exists(name): 1158 1159 if force: 1160 _LOG.debug("Forcing manifest download.") 1161 os.remove(name) 1162 1163 return await self.download_manifest(language, name, force=force) 1164 1165 else: 1166 raise FileExistsError( 1167 "Manifest file already exists, " 1168 "If you want to force download, set the `force` parameter to `True`." 1169 ) 1170 1171 _LOG.debug("Downloading manifest...") 1172 data_bytes = await self.read_manifest_bytes(language) 1173 await asyncio.get_running_loop().run_in_executor( 1174 None, _write_sqlite_bytes, data_bytes, name 1175 )
A helper method to download the manifest.
Note
This method downloads the sqlite database and not JSON.
Use RESTInterface.download_json_manifest for the JSON version.
Parameters
- language (
str): The manifest language to download, Default is english. - name (
str): The manifest database file name. Default ismanifest.sqlite3 - force (
bool): Whether to force the download. Default isFalse. However if set to true the old file will get removed and a new one will being to download.
Returns
None
1177 async def download_json_manifest(self, language: str = "en") -> None: 1178 _ensure_manifest_language(language) 1179 1180 _LOG.debug("Downloading manifest JSON...") 1181 1182 content = await self.fetch_manifest_path() 1183 json_bytes = await self._request( 1184 RequestMethod.GET, 1185 content["jsonWorldContentPaths"][language], 1186 unwrapping="read", 1187 base=True, 1188 ) 1189 1190 await asyncio.get_running_loop().run_in_executor( 1191 None, _write_json_bytes, json_bytes 1192 ) 1193 _LOG.debug("Finished downloading manifest JSON.")
Download the Bungie manifest json file.
Parameters
- language (
str): The language to download the manifest in.
1195 async def fetch_manifest_version(self) -> str: 1196 return typing.cast(str, (await self.fetch_manifest_path())["version"])
Fetch the manifest version.
Returns
str: The manifest version.
1198 @staticmethod 1199 @helpers.deprecated( 1200 since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect" 1201 ) 1202 def connect_manifest( 1203 path: typing.Optional[pathlib.Path] = None, 1204 connection: type[sqlite3.Connection] = sqlite3.Connection, 1205 ) -> sqlite3.Connection: 1206 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1207 path = path or pathlib.Path("./manifest.sqlite3") 1208 if not path.exists(): 1209 raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.") 1210 return connection(path.name)
A helper method to connect to the manifest database.
Parameters
- path (
typing.Optional[pathlib.Path]): An optional path to pass, The assumed path to connect to is './manifest.sqlite3' - connection (
type[sqlite3.Connection]): An optional connection to pass, if not passed a new connection will be created.
Returns
sqlite3.Connection: An SQLite database connection.
1212 async def fetch_linked_profiles( 1213 self, 1214 member_id: int, 1215 member_type: typedefs.IntAnd[enums.MembershipType], 1216 /, 1217 *, 1218 all: bool = False, 1219 ) -> typedefs.JSONObject: 1220 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1221 resp = await self._request( 1222 RequestMethod.GET, 1223 f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}", 1224 ) 1225 assert isinstance(resp, dict) 1226 return resp
Returns a summary information about all profiles linked to the requested member.
The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
It will only return linked accounts whose linkages you are allowed to view.
Parameters
- member_id (
int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The type for the membership whose linked Destiny account you want to return.
Other Parameters
all (
bool): If provided and set toTrue, All memberships regardless of whether thry're obscured by overrides will be returned,If provided and set to
False, Only available memberships will be returned. The default for this isFalse.
Returns
aiobungie.typedefs.JSONObject- A JSON object which contains an Array of profiles, an Array of profiles with errors and Bungie.Net membership
1236 async def fetch_public_milestones(self) -> typedefs.JSONObject: 1237 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1238 resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/") 1239 assert isinstance(resp, dict) 1240 return resp
Fetch the available milestones.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information about the milestones.
1242 async def fetch_public_milestone_content( 1243 self, milestone_hash: int, / 1244 ) -> typedefs.JSONObject: 1245 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1246 resp = await self._request( 1247 RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/" 1248 ) 1249 assert isinstance(resp, dict) 1250 return resp
Fetch the milestone content given its hash.
Parameters
- milestone_hash (
int): The milestone hash.
Returns
aiobungie.typedefs.JSONObject: A JSON object of information related to the fetched milestone.
1252 async def fetch_current_user_memberships( 1253 self, access_token: str, / 1254 ) -> typedefs.JSONObject: 1255 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1256 resp = await self._request( 1257 RequestMethod.GET, 1258 "User/GetMembershipsForCurrentUser/", 1259 auth=access_token, 1260 ) 1261 assert isinstance(resp, dict) 1262 return resp
Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.
This requires OAuth2 scope enabled and the valid Bearer access_token.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the bungie net user and destiny memberships of this account.
1264 async def equip_item( 1265 self, 1266 access_token: str, 1267 /, 1268 item_id: int, 1269 character_id: int, 1270 membership_type: typedefs.IntAnd[enums.MembershipType], 1271 ) -> None: 1272 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1273 payload = { 1274 "itemId": item_id, 1275 "characterId": character_id, 1276 "membershipType": int(membership_type), 1277 } 1278 1279 await self._request( 1280 RequestMethod.POST, 1281 "Destiny2/Actions/Items/EquipItem/", 1282 json=payload, 1283 auth=access_token, 1284 )
Equip an item to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item id. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1286 async def equip_items( 1287 self, 1288 access_token: str, 1289 /, 1290 item_ids: list[int], 1291 character_id: int, 1292 membership_type: typedefs.IntAnd[enums.MembershipType], 1293 ) -> None: 1294 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1295 payload = { 1296 "itemIds": item_ids, 1297 "characterId": character_id, 1298 "membershipType": int(membership_type), 1299 } 1300 await self._request( 1301 RequestMethod.POST, 1302 "Destiny2/Actions/Items/EquipItems/", 1303 json=payload, 1304 auth=access_token, 1305 )
Equip multiple items to a character.
This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_ids (
list[int]): A list of item ids. - character_id (
int): The character's id to equip the item to. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
1307 async def ban_clan_member( 1308 self, 1309 access_token: str, 1310 /, 1311 group_id: int, 1312 membership_id: int, 1313 membership_type: typedefs.IntAnd[enums.MembershipType], 1314 *, 1315 length: int = 0, 1316 comment: undefined.UndefinedOr[str] = undefined.Undefined, 1317 ) -> None: 1318 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1319 payload = {"comment": str(comment), "length": length} 1320 await self._request( 1321 RequestMethod.POST, 1322 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/", 1323 json=payload, 1324 auth=access_token, 1325 )
Bans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to ban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
- length (
int): An optional ban length. - comment (
aiobungie.UndefinedOr[str]): An optional comment to this ban. Default isUNDEFINED
1327 async def unban_clan_member( 1328 self, 1329 access_token: str, 1330 /, 1331 group_id: int, 1332 membership_id: int, 1333 membership_type: typedefs.IntAnd[enums.MembershipType], 1334 ) -> None: 1335 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1336 await self._request( 1337 RequestMethod.POST, 1338 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/", 1339 auth=access_token, 1340 )
Unbans a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to unban. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
1342 async def kick_clan_member( 1343 self, 1344 access_token: str, 1345 /, 1346 group_id: int, 1347 membership_id: int, 1348 membership_type: typedefs.IntAnd[enums.MembershipType], 1349 ) -> typedefs.JSONObject: 1350 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1351 resp = await self._request( 1352 RequestMethod.POST, 1353 f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/", 1354 auth=access_token, 1355 ) 1356 assert isinstance(resp, dict) 1357 return resp
Kick a member from the clan.
This request requires OAuth2: oauth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id. - membership_id (
int): The member id to kick. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the group that the member has been kicked from.
1359 async def edit_clan( 1360 self, 1361 access_token: str, 1362 /, 1363 group_id: int, 1364 *, 1365 name: typedefs.NoneOr[str] = None, 1366 about: typedefs.NoneOr[str] = None, 1367 motto: typedefs.NoneOr[str] = None, 1368 theme: typedefs.NoneOr[str] = None, 1369 tags: typedefs.NoneOr[collections.Sequence[str]] = None, 1370 is_public: typedefs.NoneOr[bool] = None, 1371 locale: typedefs.NoneOr[str] = None, 1372 avatar_image_index: typedefs.NoneOr[int] = None, 1373 membership_option: typedefs.NoneOr[ 1374 typedefs.IntAnd[enums.MembershipOption] 1375 ] = None, 1376 allow_chat: typedefs.NoneOr[bool] = None, 1377 chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None, 1378 call_sign: typedefs.NoneOr[str] = None, 1379 homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1380 enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None, 1381 default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None, 1382 is_public_topic_admin: typedefs.NoneOr[bool] = None, 1383 ) -> None: 1384 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1385 payload = { 1386 "name": name, 1387 "about": about, 1388 "motto": motto, 1389 "theme": theme, 1390 "tags": tags, 1391 "isPublic": is_public, 1392 "avatarImageIndex": avatar_image_index, 1393 "isPublicTopicAdminOnly": is_public_topic_admin, 1394 "allowChat": allow_chat, 1395 "chatSecurity": chat_security, 1396 "callsign": call_sign, 1397 "homepage": homepage, 1398 "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins, 1399 "defaultPublicity": default_publicity, 1400 "locale": locale, 1401 } 1402 if membership_option is not None: 1403 payload["membershipOption"] = int(membership_option) 1404 1405 await self._request( 1406 RequestMethod.POST, 1407 f"GroupV2/{group_id}/Edit", 1408 json=payload, 1409 auth=access_token, 1410 )
Edit a clan.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id to edit.
Other Parameters
- name (
aiobungie.typedefs.NoneOr[str]): The name to edit the clan with. - about (
aiobungie.typedefs.NoneOr[str]): The about section to edit the clan with. - motto (
aiobungie.typedefs.NoneOr[str]): The motto section to edit the clan with. - theme (
aiobungie.typedefs.NoneOr[str]): The theme name to edit the clan with. - tags (
aiobungie.typedefs.NoneOr[collections.Sequence[str]]): A sequence of strings to replace the clan tags with. - is_public (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan will set to private. If provided and set toFalse, The clan will set to public whether it was or not. - locale (
aiobungie.typedefs.NoneOr[str]): The locale section to edit the clan with. - avatar_image_index (
aiobungie.typedefs.NoneOr[int]): The clan avatar image index to edit the clan with. - membership_option :
aiobungie.typedefs.NoneOr[aiobungie.typedefs.IntAnd[aiobungie.MembershipOption]]# noqa (E501 # Line too long): The clan membership option to edit it with. - allow_chat (
aiobungie.typedefs.NoneOr[bool]): If provided and set toTrue, The clan members will be allowed to chat. If provided and set toFalse, The clan members will not be allowed to chat. - chat_security (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to0, The clan chat security will be edited toGrouponly. If provided and set to1, The clan chat security will be edited toAdminonly. - call_sign (
aiobungie.typedefs.NoneOr[str]): The clan call sign to edit it with. - homepage (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat homepage will be edited toWall. If provided and set to1, The clan chat homepage will be edited toForum. If provided and set to0, The clan chat homepage will be edited toAllianceForum. - enable_invite_messaging_for_admins (
aiobungie.typedefs.NoneOr[bool]): ??? - default_publicity (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to0, The clan chat publicity will be edited toPublic. If provided and set to1, The clan chat publicity will be edited toAlliance. If provided and set to2, The clan chat publicity will be edited toPrivate. - is_public_topic_admin (
aiobungie.typedefs.NoneOr[bool]): ???
1412 async def edit_clan_options( 1413 self, 1414 access_token: str, 1415 /, 1416 group_id: int, 1417 *, 1418 invite_permissions_override: typedefs.NoneOr[bool] = None, 1419 update_culture_permissionOverride: typedefs.NoneOr[bool] = None, 1420 host_guided_game_permission_override: typedefs.NoneOr[ 1421 typing.Literal[0, 1, 2] 1422 ] = None, 1423 update_banner_permission_override: typedefs.NoneOr[bool] = None, 1424 join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None, 1425 ) -> None: 1426 1427 payload = { 1428 "InvitePermissionOverride": invite_permissions_override, 1429 "UpdateCulturePermissionOverride": update_culture_permissionOverride, 1430 "HostGuidedGamePermissionOverride": host_guided_game_permission_override, 1431 "UpdateBannerPermissionOverride": update_banner_permission_override, 1432 "JoinLevel": int(join_level) if join_level else None, 1433 } 1434 1435 await self._request( 1436 RequestMethod.POST, 1437 f"GroupV2/{group_id}/EditFounderOptions", 1438 json=payload, 1439 auth=access_token, 1440 )
Edit the clan options.
Notes
- This request requires OAuth2: oauth2:
AdminGroupsscope. - All arguments will default to
Noneif not provided. This does not includeaccess_tokenandgroup_id
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group id.
Other Parameters
- invite_permissions_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - update_culture_permissionOverride (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - host_guided_game_permission_override (
aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides:0-> None,1-> Beginner2-> Member. Default is Member for clans, None for groups, although this means nothing for groups. - update_banner_permission_override (
aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups. - join_level (
aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default isaiobungie.ClanMemberType.BEGINNER
1442 async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject: 1443 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1444 resp = await self._request( 1445 RequestMethod.GET, 1446 "Social/Friends/", 1447 auth=access_token, 1448 ) 1449 assert isinstance(resp, dict) 1450 return resp
Fetch bungie friend list.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of an array of the bungie friends's data.
1452 async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject: 1453 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1454 resp = await self._request( 1455 RequestMethod.GET, 1456 "Social/Friends/Requests", 1457 auth=access_token, 1458 ) 1459 assert isinstance(resp, dict) 1460 return resp
Fetch pending bungie friend requests queue.
This requests OAuth2: ReadUserData scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account.
Returns
aiobungie.typedefs.JSONObject: A JSON object of incoming requests and outgoing requests.
1462 async def accept_friend_request(self, access_token: str, /, member_id: int) -> None: 1463 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1464 await self._request( 1465 RequestMethod.POST, 1466 f"Social/Friends/Requests/Accept/{member_id}", 1467 auth=access_token, 1468 )
Accepts a friend relationship with the target user. The user must be on your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to accept.
1470 async def send_friend_request(self, access_token: str, /, member_id: int) -> None: 1471 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1472 await self._request( 1473 RequestMethod.POST, 1474 f"Social/Friends/Add/{member_id}", 1475 auth=access_token, 1476 )
Requests a friend relationship with the target user.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to send the request to.
1478 async def decline_friend_request( 1479 self, access_token: str, /, member_id: int 1480 ) -> None: 1481 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1482 await self._request( 1483 RequestMethod.POST, 1484 f"Social/Friends/Requests/Decline/{member_id}", 1485 auth=access_token, 1486 )
Decline a friend request with the target user. The user must be in your incoming friend request list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to decline.
1488 async def remove_friend(self, access_token: str, /, member_id: int) -> None: 1489 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1490 await self._request( 1491 RequestMethod.POST, 1492 f"Social/Friends/Remove/{member_id}", 1493 auth=access_token, 1494 )
Removes a friend from your friend list. The user must be in your friend list.
This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove.
1496 async def remove_friend_request(self, access_token: str, /, member_id: int) -> None: 1497 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1498 await self._request( 1499 RequestMethod.POST, 1500 f"Social/Friends/Requests/Remove/{member_id}", 1501 auth=access_token, 1502 )
Removes a friend from your friend list requests. The user must be in your outgoing request list.
.. note : This request requires OAuth2: BnetWrite scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - member_id (
int): The member's id to remove from the requested friend list.
1504 async def approve_all_pending_group_users( 1505 self, 1506 access_token: str, 1507 /, 1508 group_id: int, 1509 message: undefined.UndefinedOr[str] = undefined.Undefined, 1510 ) -> None: 1511 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1512 await self._request( 1513 RequestMethod.POST, 1514 f"GroupV2/{group_id}/Members/ApproveAll", 1515 auth=access_token, 1516 json={"message": str(message)}, 1517 )
Apporve all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1519 async def deny_all_pending_group_users( 1520 self, 1521 access_token: str, 1522 /, 1523 group_id: int, 1524 *, 1525 message: undefined.UndefinedOr[str] = undefined.Undefined, 1526 ) -> None: 1527 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1528 await self._request( 1529 RequestMethod.POST, 1530 f"GroupV2/{group_id}/Members/DenyAll", 1531 auth=access_token, 1532 json={"message": str(message)}, 1533 )
Deny all pending users for the given group id.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other Parameters
- message (
aiobungie.UndefinedOr[str]): An optional message to send with the request. Default isUNDEFINED.
1535 async def add_optional_conversation( 1536 self, 1537 access_token: str, 1538 /, 1539 group_id: int, 1540 *, 1541 name: undefined.UndefinedOr[str] = undefined.Undefined, 1542 security: typing.Literal[0, 1] = 0, 1543 ) -> None: 1544 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1545 payload = {"chatName": str(name), "chatSecurity": security} 1546 await self._request( 1547 RequestMethod.POST, 1548 f"GroupV2/{group_id}/OptionalConversations/Add", 1549 json=payload, 1550 auth=access_token, 1551 )
Add a new chat channel to a group.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id.
Other parameters
name: aiobungie.UndefinedOr[str]
The chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
1553 async def edit_optional_conversation( 1554 self, 1555 access_token: str, 1556 /, 1557 group_id: int, 1558 conversation_id: int, 1559 *, 1560 name: undefined.UndefinedOr[str] = undefined.Undefined, 1561 security: typing.Literal[0, 1] = 0, 1562 enable_chat: bool = False, 1563 ) -> None: 1564 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1565 payload = { 1566 "chatEnabled": enable_chat, 1567 "chatName": str(name), 1568 "chatSecurity": security, 1569 } 1570 await self._request( 1571 RequestMethod.POST, 1572 f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}", 1573 json=payload, 1574 auth=access_token, 1575 )
Edit the settings of this chat channel.
This request requires OAuth2: AdminGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The given group id. - conversation_id (
int): The conversation/chat id.
Other parameters
name: aiobungie.UndefinedOr[str]
The new chat name. Default to UNDEFINED
security: typing.Literal[0, 1]
The new security level of the chat.
If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
enable_chat : bool
Whether to enable chatting or not.
If set to True then chatting will be enabled. Otherwise it will be disabled.
1577 async def transfer_item( 1578 self, 1579 access_token: str, 1580 /, 1581 item_id: int, 1582 item_hash: int, 1583 character_id: int, 1584 member_type: typedefs.IntAnd[enums.MembershipType], 1585 *, 1586 stack_size: int = 1, 1587 vault: bool = False, 1588 ) -> None: 1589 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1590 payload = { 1591 "characterId": character_id, 1592 "membershipType": int(member_type), 1593 "itemId": item_id, 1594 "itemReferenceHash": item_hash, 1595 "stackSize": stack_size, 1596 "transferToVault": vault, 1597 } 1598 await self._request( 1599 RequestMethod.POST, 1600 "Destiny2/Actions/Items/TransferItem", 1601 json=payload, 1602 auth=access_token, 1603 )
Transfer an item from / to your vault.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id you to transfer. - item_hash (
int): The item hash. - character_id (
int): The character id to transfer the item from/to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to trasnfer this item to your valut or not. Defaults toFalse.
1605 async def pull_item( 1606 self, 1607 access_token: str, 1608 /, 1609 item_id: int, 1610 item_hash: int, 1611 character_id: int, 1612 member_type: typedefs.IntAnd[enums.MembershipType], 1613 *, 1614 stack_size: int = 1, 1615 vault: bool = False, 1616 ) -> None: 1617 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>> 1618 payload = { 1619 "characterId": character_id, 1620 "membershipType": int(member_type), 1621 "itemId": item_id, 1622 "itemReferenceHash": item_hash, 1623 "stackSize": stack_size, 1624 "transferToVault": vault, 1625 } 1626 await self._request( 1627 RequestMethod.POST, 1628 "Destiny2/Actions/Items/PullFromPostmaster", 1629 json=payload, 1630 auth=access_token, 1631 )
pull an item from the postmaster.
Notes
- This method requires OAuth2: MoveEquipDestinyItems scope.
- This method requires both item id and hash.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - item_id (
int): The item instance id to pull. - item_hash (
int): The item hash. - character_id (
int): The character id to pull the item to. - member_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
- stack_size (
int): The item stack size. - valut (
bool): Whether to pill this item to your valut or not. Defaults toFalse.
1633 async def fetch_fireteams( 1634 self, 1635 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1636 *, 1637 platform: typedefs.IntAnd[ 1638 fireteams.FireteamPlatform 1639 ] = fireteams.FireteamPlatform.ANY, 1640 language: typing.Union[ 1641 fireteams.FireteamLanguage, str 1642 ] = fireteams.FireteamLanguage.ALL, 1643 date_range: typedefs.IntAnd[ 1644 fireteams.FireteamDate 1645 ] = fireteams.FireteamDate.ALL, 1646 page: int = 0, 1647 slots_filter: int = 0, 1648 ) -> typedefs.JSONObject: 1649 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1650 resp = await self._request( 1651 RequestMethod.GET, 1652 f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}", # noqa: E501 Line too long 1653 ) 1654 assert isinstance(resp, dict) 1655 return resp
Fetch public Bungie fireteams with open slots.
Parameters
- activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1657 async def fetch_avaliable_clan_fireteams( 1658 self, 1659 access_token: str, 1660 group_id: int, 1661 activity_type: typedefs.IntAnd[fireteams.FireteamActivity], 1662 *, 1663 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1664 language: typing.Union[fireteams.FireteamLanguage, str], 1665 date_range: typedefs.IntAnd[ 1666 fireteams.FireteamDate 1667 ] = fireteams.FireteamDate.ALL, 1668 page: int = 0, 1669 public_only: bool = False, 1670 slots_filter: int = 0, 1671 ) -> typedefs.JSONObject: 1672 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1673 resp = await self._request( 1674 RequestMethod.GET, 1675 f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}", # noqa: E501 1676 json={"langFilter": str(language)}, 1677 auth=access_token, 1678 ) 1679 assert isinstance(resp, dict) 1680 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id of the fireteam. - activity_type (
aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
- platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - date_range (
aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults toaiobungie.FireteamDate.ALL. - page (
int): The page number. By default its0which returns all available activities. - public_only (
bool): If set to True, Then only public fireteams will be returned. - slots_filter (
int): Filter the returned fireteams based on available slots. Default is0
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1682 async def fetch_clan_fireteam( 1683 self, access_token: str, fireteam_id: int, group_id: int 1684 ) -> typedefs.JSONObject: 1685 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1686 resp = await self._request( 1687 RequestMethod.GET, 1688 f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}", 1689 auth=access_token, 1690 ) 1691 assert isinstance(resp, dict) 1692 return resp
Fetch a specific clan fireteam.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch the fireteam from. - fireteam_id (
int): The fireteam id to fetch.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteam details.
1694 async def fetch_my_clan_fireteams( 1695 self, 1696 access_token: str, 1697 group_id: int, 1698 *, 1699 include_closed: bool = True, 1700 platform: typedefs.IntAnd[fireteams.FireteamPlatform], 1701 language: typing.Union[fireteams.FireteamLanguage, str], 1702 filtered: bool = True, 1703 page: int = 0, 1704 ) -> typedefs.JSONObject: 1705 payload = {"groupFilter": filtered, "langFilter": str(language)} 1706 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1707 resp = await self._request( 1708 RequestMethod.GET, 1709 f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}", 1710 json=payload, 1711 auth=access_token, 1712 ) 1713 assert isinstance(resp, dict) 1714 return resp
Fetch a clan's fireteams with open slots.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id to fetch.
Other Parameters
- include_closed (
bool): If provided and set toTrue, It will also return closed fireteams. If provided and set toFalse, It will only return public fireteams. Default isTrue. - platform (
aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults toaiobungie.crates.FireteamPlatform.ANYwhich returns all platforms. - language (
typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults toaiobungie.crates.FireteamLanguage.ALL - filtered (
bool): If set toTrue, it will filter by clan. Otherwise not. Default isTrue. - page (
int): The page number. By default its0which returns all available activities.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the fireteams detail.
1716 async def fetch_private_clan_fireteams( 1717 self, access_token: str, group_id: int, / 1718 ) -> int: 1719 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1720 resp = await self._request( 1721 RequestMethod.GET, 1722 f"Fireteam/Clan/{group_id}/ActiveCount", 1723 auth=access_token, 1724 ) 1725 assert isinstance(resp, int) 1726 return resp
Fetch the active count of the clan fireteams that are only private.
This method requires OAuth2: ReadGroups scope.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - group_id (
int): The group/clan id.
Returns
int: The active fireteams count. Max value returned is 25.
1728 async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject: 1729 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1730 resp = await self._request( 1731 RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}" 1732 ) 1733 assert isinstance(resp, dict) 1734 return resp
Fetch a post activity details.
Parameters
- instance_id (
int): The activity instance id.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the post activity.
1736 async def search_entities( 1737 self, name: str, entity_type: str, *, page: int = 0 1738 ) -> typedefs.JSONObject: 1739 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1740 resp = await self._request( 1741 RequestMethod.GET, 1742 f"Destiny2/Armory/Search/{entity_type}/{name}/", 1743 json={"page": page}, 1744 ) 1745 assert isinstance(resp, dict) 1746 return resp
Search for Destiny2 entities given a name and its type.
Parameters
- name (
str): The name of the entity, i.e., Thunderlord, One thousand voices. - entity_type (
str): The type of the entity, AKA Definition, For an exampleDestinyInventoryItemDefinition
Other Parameters
- page (
int): An optional page to return. Default to 0.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the searched term.
1748 async def fetch_unique_weapon_history( 1749 self, 1750 membership_id: int, 1751 character_id: int, 1752 membership_type: typedefs.IntAnd[enums.MembershipType], 1753 ) -> typedefs.JSONObject: 1754 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1755 resp = await self._request( 1756 RequestMethod.GET, 1757 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/", 1758 ) 1759 assert isinstance(resp, dict) 1760 return resp
Fetch details about unique weapon usage for a character. Includes all exotics.
Parameters
- membership_id (
int): The Destiny user membership id. - character_id (
int): The character id to retrieve. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny user's membership type.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains details about the returned weapons.
1762 async def fetch_item( 1763 self, 1764 member_id: int, 1765 item_id: int, 1766 membership_type: typedefs.IntAnd[enums.MembershipType], 1767 components: list[enums.ComponentType], 1768 ) -> typedefs.JSONObject: 1769 collector = _collect_components(components) 1770 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1771 resp = await self._request( 1772 RequestMethod.GET, 1773 f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}", 1774 ) 1775 assert isinstance(resp, dict) 1776 return resp
Fetch an instanced Destiny 2 item's details.
Parameters
- member_id (
int): The membership id of the Destiny 2 player. - item_id (
int): The instance id of the item. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type of the Destiny 2 player. - components (
list[aiobungie.ComponentType]): A list of components to retrieve.
Returns
aiobungie.typedefs.JSONObject: A JSON object response contains the fetched item with its components.
1778 async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject: 1779 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1780 resp = await self._request( 1781 RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/" 1782 ) 1783 assert isinstance(resp, dict) 1784 return resp
Fetch the weekly reward state for a clan.
Parameters
- clan_id (
int): The clan id.
Returns
aiobungie.typedefs.JSONObject: A JSON response of the clan rewards state.
1786 async def fetch_available_locales(self) -> typedefs.JSONObject: 1787 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1788 resp = await self._request( 1789 RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/" 1790 ) 1791 assert isinstance(resp, dict) 1792 return resp
Fetch available locales at Bungie.
Returns
aiobungie.typedefs.JSONObject: A JSON object contains a list of all available localization cultures.
1794 async def fetch_common_settings(self) -> typedefs.JSONObject: 1795 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1796 resp = await self._request(RequestMethod.GET, "Settings") 1797 assert isinstance(resp, dict) 1798 return resp
Fetch the common settings used by Bungie's envirotment.
Returns
aiobungie.typedefs.JSONObject: The common settings JSON object.
1800 async def fetch_user_systems_overrides(self) -> typedefs.JSONObject: 1801 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1802 resp = await self._request(RequestMethod.GET, "UserSystemOverrides") 1803 assert isinstance(resp, dict) 1804 return resp
Fetch a user's specific system overrides.
Returns
aiobungie.typedefs.JSONObject: The system overrides JSON object.
1806 async def fetch_global_alerts( 1807 self, *, include_streaming: bool = False 1808 ) -> typedefs.JSONArray: 1809 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1810 resp = await self._request( 1811 RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}" 1812 ) 1813 assert isinstance(resp, list) 1814 return resp
Fetch any active global alerts.
Parameters
- include_streaming (
bool): If True, the returned results will include streaming alerts. Default is False.
Returns
aiobungie.typedefs.JSONArray: A JSON array of the global alerts objects.
1816 async def awainitialize_request( 1817 self, 1818 access_token: str, 1819 type: typing.Literal[0, 1], 1820 membership_type: typedefs.IntAnd[enums.MembershipType], 1821 /, 1822 *, 1823 affected_item_id: typing.Optional[int] = None, 1824 character_id: typing.Optional[int] = None, 1825 ) -> typedefs.JSONObject: 1826 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1827 1828 body = {"type": type, "membershipType": int(membership_type)} 1829 1830 if affected_item_id is not None: 1831 body["affectedItemId"] = affected_item_id 1832 1833 if character_id is not None: 1834 body["characterId"] = character_id 1835 1836 resp = await self._request( 1837 RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token 1838 ) 1839 assert isinstance(resp, dict) 1840 return resp
Initialize a request to perform an advanced write action.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - type (
typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means itNone. Otherwise if 1 that means its insert plugs. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
- affected_item_id (
typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values. - character_id (
typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1842 async def awaget_action_token( 1843 self, access_token: str, correlation_id: str, / 1844 ) -> typedefs.JSONObject: 1845 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1846 resp = await self._request( 1847 RequestMethod.POST, 1848 f"Destiny2/Awa/GetActionToken/{correlation_id}", 1849 auth=access_token, 1850 ) 1851 assert isinstance(resp, dict) 1852 return resp
Returns the action token if user approves the request.
OAuth2: AdvancedWriteActions application scope is required to perform this request.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - correlation_id (
str): The identifier for the advanced write action request.
Returns
aiobungie.typedefs.JSONObject: A JSON object response.
1874 async def fetch_vendors( 1875 self, 1876 access_token: str, 1877 character_id: int, 1878 membership_id: int, 1879 membership_type: typedefs.IntAnd[enums.MembershipType], 1880 /, 1881 components: list[enums.ComponentType], 1882 filter: typing.Optional[int] = None, 1883 ) -> typedefs.JSONObject: 1884 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1885 components_ = _collect_components(components) 1886 route = ( 1887 f"Destiny2/{int(membership_type)}/Profile/{membership_id}" 1888 f"/Character/{character_id}/Vendors/?components={components_}" 1889 ) 1890 1891 if filter is not None: 1892 route = route + f"&filter={filter}" 1893 1894 resp = await self._request( 1895 RequestMethod.GET, 1896 route, 1897 auth=access_token, 1898 ) 1899 assert isinstance(resp, dict) 1900 return resp
Get currently available vendors from the list of vendors that can possibly have rotating inventory.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
- filter (
int): Filters the type of items returned from the vendor. This can be left toNone.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1902 async def fetch_vendor( 1903 self, 1904 access_token: str, 1905 character_id: int, 1906 membership_id: int, 1907 membership_type: typedefs.IntAnd[enums.MembershipType], 1908 vendor_hash: int, 1909 /, 1910 components: list[enums.ComponentType], 1911 ) -> typedefs.JSONObject: 1912 # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>. 1913 components_ = _collect_components(components) 1914 resp = await self._request( 1915 RequestMethod.GET, 1916 ( 1917 f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}" 1918 f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}" 1919 ), 1920 auth=access_token, 1921 ) 1922 assert isinstance(resp, dict) 1923 return resp
Fetch details for a specific vendor.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - character_id (
int): The character ID to return the vendor info for. - membership_id (
int): The Destiny membership id to return the vendor info for. - membership_type (
aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for. - vendor_hash (
int): The vendor hash to return the details for. - components (
list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the vendor response.
1925 async def fetch_application_api_usage( 1926 self, 1927 access_token: str, 1928 application_id: int, 1929 /, 1930 *, 1931 start: typing.Optional[datetime.datetime] = None, 1932 end: typing.Optional[datetime.datetime] = None, 1933 ) -> typedefs.JSONObject: 1934 1935 end_date, start_date = time.parse_date_range(end, start) 1936 resp = await self._request( 1937 RequestMethod.GET, 1938 f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}", 1939 auth=access_token, 1940 ) 1941 assert isinstance(resp, dict) 1942 return resp
Fetch a Bungie application's API usage.
Parameters
- access_token (
str): The bearer access token associated with the bungie account. - application_id (
int): The application id to get.
Other Parameters
start (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.If this is left to
None. It will return the last 24 hours.end (
typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.If this is left to
None. It will returnnow.
Example
import datetime
# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
aiobungie.typedefs.JSONObject: A JSON object of the application usage details.
1944 async def fetch_bungie_applications(self) -> typedefs.JSONArray: 1945 resp = await self._request(RequestMethod.GET, "App/FirstParty") 1946 assert isinstance(resp, list) 1947 return resp
Fetch details for applications created by Bungie.
Returns
aiobungie.typedefs.JSONArray: An array of Bungie created applications.
1954 async def fetch_content_by_id( 1955 self, id: int, locale: str, /, *, head: bool = False 1956 ) -> typedefs.JSONObject: 1957 resp = await self._request( 1958 RequestMethod.GET, 1959 f"Content/GetContentById/{id}/{locale}/", 1960 json={"head": head}, 1961 ) 1962 assert isinstance(resp, dict) 1963 return resp
1965 async def fetch_content_by_tag_and_type( 1966 self, locale: str, tag: str, type: str, *, head: bool = False 1967 ) -> typedefs.JSONObject: 1968 resp = await self._request( 1969 RequestMethod.GET, 1970 f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/", 1971 json={"head": head}, 1972 ) 1973 assert isinstance(resp, dict) 1974 return resp
1976 async def search_content_with_text( 1977 self, 1978 locale: str, 1979 /, 1980 content_type: str, 1981 search_text: str, 1982 tag: str, 1983 *, 1984 page: undefined.UndefinedOr[int] = undefined.Undefined, 1985 source: undefined.UndefinedOr[str] = undefined.Undefined, 1986 ) -> typedefs.JSONObject: 1987 1988 body: typedefs.JSONObject = {} 1989 1990 body["ctype"] = content_type 1991 body["searchtext"] = search_text 1992 body["tag"] = tag 1993 1994 if page is not undefined.Undefined: 1995 body["currentpage"] = page 1996 else: 1997 body["currentpage"] = 1 1998 1999 if source is not undefined.Undefined: 2000 body["source"] = source 2001 else: 2002 source = "" 2003 resp = await self._request( 2004 RequestMethod.GET, f"Content/Search/{locale}/", json=body 2005 ) 2006 assert isinstance(resp, dict) 2007 return resp
2009 async def search_content_by_tag_and_type( 2010 self, 2011 locale: str, 2012 tag: str, 2013 type: str, 2014 *, 2015 page: undefined.UndefinedOr[int] = undefined.Undefined, 2016 ) -> typedefs.JSONObject: 2017 body: typedefs.JSONObject = {} 2018 body["currentpage"] = 1 if page is undefined.Undefined else page 2019 resp = await self._request( 2020 RequestMethod.GET, 2021 f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/", 2022 json=body, 2023 ) 2024 assert isinstance(resp, dict) 2025 return resp
2036 async def fetch_topics_page( 2037 self, 2038 category_filter: int, 2039 group: int, 2040 date_filter: int, 2041 sort: typing.Union[str, bytes], 2042 *, 2043 page: undefined.UndefinedOr[int] = undefined.Undefined, 2044 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2045 tag_filter: undefined.UndefinedOr[str] = undefined.Undefined, 2046 ) -> typedefs.JSONObject: 2047 2048 body: typedefs.JSONObject = {} 2049 if locales is not undefined.Undefined: 2050 body["locales"] = ",".join(str(locales)) 2051 else: 2052 body["locales"] = ",".join([]) 2053 2054 if tag_filter is not undefined.Undefined: 2055 body["tagstring"] = tag_filter 2056 else: 2057 body["tagstring"] = "" 2058 2059 page = 0 if page is not undefined.Undefined else page 2060 2061 resp = await self._request( 2062 RequestMethod.GET, 2063 f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/", 2064 json=body, 2065 ) 2066 assert isinstance(resp, dict) 2067 return resp
2069 async def fetch_core_topics_page( 2070 self, 2071 category_filter: int, 2072 date_filter: int, 2073 sort: typing.Union[str, bytes], 2074 *, 2075 page: undefined.UndefinedOr[int] = undefined.Undefined, 2076 locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined, 2077 ) -> typedefs.JSONObject: 2078 body: typedefs.JSONObject = {} 2079 2080 if locales is not undefined.Undefined: 2081 body["locales"] = ",".join(str(locales)) 2082 else: 2083 body["locales"] = ",".join([]) 2084 2085 resp = await self._request( 2086 RequestMethod.GET, 2087 f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}" 2088 f"/{sort!s}/{date_filter}/{category_filter}/", 2089 json=body, 2090 ) 2091 assert isinstance(resp, dict) 2092 return resp
2094 async def fetch_posts_threaded_page( 2095 self, 2096 parent_post: bool, 2097 page: int, 2098 page_size: int, 2099 parent_post_id: int, 2100 reply_size: int, 2101 root_thread_mode: bool, 2102 sort_mode: int, 2103 show_banned: typing.Optional[str] = None, 2104 ) -> typedefs.JSONObject: 2105 resp = await self._request( 2106 RequestMethod.GET, 2107 f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/" 2108 f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/", 2109 json={"showbanned": show_banned}, 2110 ) 2111 assert isinstance(resp, dict) 2112 return resp
2114 async def fetch_posts_threaded_page_from_child( 2115 self, 2116 child_id: bool, 2117 page: int, 2118 page_size: int, 2119 reply_size: int, 2120 root_thread_mode: bool, 2121 sort_mode: int, 2122 show_banned: typing.Optional[str] = None, 2123 ) -> typedefs.JSONObject: 2124 resp = await self._request( 2125 RequestMethod.GET, 2126 f"Forum/GetPostsThreadedPagedFromChild/{child_id}/" 2127 f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/", 2128 json={"showbanned": show_banned}, 2129 ) 2130 assert isinstance(resp, dict) 2131 return resp
2133 async def fetch_post_and_parent( 2134 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2135 ) -> typedefs.JSONObject: 2136 resp = await self._request( 2137 RequestMethod.GET, 2138 f"Forum/GetPostAndParent/{child_id}/", 2139 json={"showbanned": show_banned}, 2140 ) 2141 assert isinstance(resp, dict) 2142 return resp
2144 async def fetch_posts_and_parent_awaiting( 2145 self, child_id: int, /, *, show_banned: typing.Optional[str] = None 2146 ) -> typedefs.JSONObject: 2147 resp = await self._request( 2148 RequestMethod.GET, 2149 f"Forum/GetPostAndParentAwaitingApproval/{child_id}/", 2150 json={"showbanned": show_banned}, 2151 ) 2152 assert isinstance(resp, dict) 2153 return resp
2183 async def fetch_recommended_groups( 2184 self, 2185 accecss_token: str, 2186 /, 2187 *, 2188 date_range: int = 0, 2189 group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN, 2190 ) -> typedefs.JSONArray: 2191 resp = await self._request( 2192 RequestMethod.POST, 2193 f"GroupV2/Recommended/{int(group_type)}/{date_range}/", 2194 auth=accecss_token, 2195 ) 2196 assert isinstance(resp, list) 2197 return resp
2204 async def fetch_user_clan_invite_setting( 2205 self, 2206 access_token: str, 2207 /, 2208 membership_type: typedefs.IntAnd[enums.MembershipType], 2209 ) -> bool: 2210 resp = await self._request( 2211 RequestMethod.GET, 2212 f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/", 2213 auth=access_token, 2214 ) 2215 assert isinstance(resp, bool) 2216 return resp
2218 async def fetch_banned_group_members( 2219 self, access_token: str, group_id: int, /, *, page: int = 1 2220 ) -> typedefs.JSONObject: 2221 resp = await self._request( 2222 RequestMethod.GET, 2223 f"GroupV2/{group_id}/Banned/?currentpage={page}", 2224 auth=access_token, 2225 ) 2226 assert isinstance(resp, dict) 2227 return resp
2229 async def fetch_pending_group_memberships( 2230 self, access_token: str, group_id: int, /, *, current_page: int = 1 2231 ) -> typedefs.JSONObject: 2232 resp = await self._request( 2233 RequestMethod.GET, 2234 f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}", 2235 auth=access_token, 2236 ) 2237 assert isinstance(resp, dict) 2238 return resp
2240 async def fetch_invited_group_memberships( 2241 self, access_token: str, group_id: int, /, *, current_page: int = 1 2242 ) -> typedefs.JSONObject: 2243 resp = await self._request( 2244 RequestMethod.GET, 2245 f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}", 2246 auth=access_token, 2247 ) 2248 assert isinstance(resp, dict) 2249 return resp
2251 async def invite_member_to_group( 2252 self, 2253 access_token: str, 2254 /, 2255 group_id: int, 2256 membership_id: int, 2257 membership_type: typedefs.IntAnd[enums.MembershipType], 2258 *, 2259 message: undefined.UndefinedOr[str] = undefined.Undefined, 2260 ) -> typedefs.JSONObject: 2261 resp = await self._request( 2262 RequestMethod.POST, 2263 f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/", 2264 auth=access_token, 2265 json={"message": str(message)}, 2266 ) 2267 assert isinstance(resp, dict) 2268 return resp
2270 async def cancel_group_member_invite( 2271 self, 2272 access_token: str, 2273 /, 2274 group_id: int, 2275 membership_id: int, 2276 membership_type: typedefs.IntAnd[enums.MembershipType], 2277 ) -> typedefs.JSONObject: 2278 resp = await self._request( 2279 RequestMethod.POST, 2280 f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/", 2281 auth=access_token, 2282 ) 2283 assert isinstance(resp, dict) 2284 return resp
2291 async def fetch_historical_stats( 2292 self, 2293 character_id: int, 2294 membership_id: int, 2295 membership_type: typedefs.IntAnd[enums.MembershipType], 2296 day_start: datetime.datetime, 2297 day_end: datetime.datetime, 2298 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2299 modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]], 2300 *, 2301 period_type: enums.PeriodType = enums.PeriodType.ALL_TIME, 2302 ) -> typedefs.JSONObject: 2303 2304 end, start = time.parse_date_range(day_end, day_start) 2305 resp = await self._request( 2306 RequestMethod.GET, 2307 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/", 2308 json={ 2309 "dayend": end, 2310 "daystart": start, 2311 "groups": [str(int(group)) for group in groups], 2312 "modes": [str(int(mode)) for mode in modes], 2313 "periodType": int(period_type), 2314 }, 2315 ) 2316 assert isinstance(resp, dict) 2317 return resp
Fetch historical stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - day_start (
datetime.datetime): The start of the day to return the stats for. - day_end (
datetime.datetime): The end of the day to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return. - modes (
list[aiobungie.GameMode | int]): A list of game modes to return. - period_type (
aiobungie.enums.PeriodType): The period type to return the stats for. This will returnALL_TIMEby default if not modified.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats.
2319 async def fetch_historical_stats_for_account( 2320 self, 2321 membership_id: int, 2322 membership_type: typedefs.IntAnd[enums.MembershipType], 2323 groups: list[typedefs.IntAnd[enums.StatsGroupType]], 2324 ) -> typedefs.JSONObject: 2325 resp = await self._request( 2326 RequestMethod.GET, 2327 f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/", 2328 json={"groups": [str(int(group)) for group in groups]}, 2329 ) 2330 assert isinstance(resp, dict) 2331 return resp
Fetch historical stats for an account's membership.
Parameters
- membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for. - groups (
list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the historical stats for the account. This includes both the character and account stats.
2333 async def fetch_aggregated_activity_stats( 2334 self, 2335 character_id: int, 2336 membership_id: int, 2337 membership_type: typedefs.IntAnd[enums.MembershipType], 2338 /, 2339 ) -> typedefs.JSONObject: 2340 resp = await self._request( 2341 RequestMethod.GET, 2342 f"Destiny2/{int(membership_type)}/Account/{membership_id}/" 2343 f"Character/{character_id}/Stats/AggregateActivityStats/", 2344 ) 2345 assert isinstance(resp, dict) 2346 return resp
Fetch aggregated activity stats for a specific membership character.
Parameters
- character_id (
int): The character ID to return the stats for. - membership_id (
int): The Destiny membership id to return the stats for. - membership_type (
aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
aiobungie.typedefs.JSONObject: A JSON object of the aggregated activity stats.
234class RESTPool: 235 """Pool of `RESTClient` instances. 236 237 This allows to create multiple instances of `RESTClient`s that can be acquired 238 which share the same connector and metadata. 239 240 Example 241 ------- 242 ```py 243 import aiobungie 244 245 client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret') 246 247 # Using a context manager to acquire an instance 248 # of the pool and close the connection after finishing. 249 250 async with client_pool.acquire() as client: 251 await client.download_manifest() 252 return client.build_oauth2_url() 253 254 async with client_pool.acquire() as client: 255 new_tokens = await client.refresh_access_token("token") 256 # Tokens now can be used from any pool. 257 client.metadata['tokens'] = new_tokens 258 ``` 259 260 Parameters 261 ---------- 262 token : `str` 263 A valid application token from Bungie's developer portal. 264 265 Other Parameters 266 ---------------- 267 max_retries : `int` 268 The max retries number to retry if the request hit a `5xx` status code. 269 max_ratelimit_retries : `int` 270 The max retries number to retry if the request hit a `429` status code. Defaults to `3`. 271 client_secret : `typing.Optional[str]` 272 An optional application client secret, 273 This is only needed if you're fetching OAuth2 tokens with this client. 274 client_id : `typing.Optional[int]` 275 An optional application client id, 276 This is only needed if you're fetching OAuth2 tokens with this client. 277 enable_debugging : `bool | str` 278 Whether to enable logging responses or not. 279 280 Logging Levels 281 -------------- 282 * `False`: This will disable logging. 283 * `True`: This will set the level to `DEBUG` and enable logging minimal information. 284 Like the response status, route, taken time and so on. 285 * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information. 286 """ 287 288 __slots__ = ( 289 "_token", 290 "_max_retries", 291 "_client_secret", 292 "_client_id", 293 "_max_rate_limit_retries", 294 "_metadata", 295 "_enable_debug", 296 ) 297 298 # Looks like mypy doesn't like this. 299 if typing.TYPE_CHECKING: 300 _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int] 301 302 def __init__( 303 self, 304 token: str, 305 /, 306 client_secret: typing.Optional[str] = None, 307 client_id: typing.Optional[int] = None, 308 *, 309 max_retries: int = 4, 310 max_rate_limit_retries: int = 3, 311 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 312 ) -> None: 313 self._client_secret = client_secret 314 self._client_id = client_id 315 self._token: str = token 316 self._max_retries = max_retries 317 self._max_rate_limit_retries = max_rate_limit_retries 318 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 319 self._enable_debug = enable_debugging 320 321 @property 322 def client_id(self) -> typing.Optional[int]: 323 return self._client_id 324 325 @property 326 def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]: 327 """Pool's Metadata. This is different from client instance metadata.""" 328 return self._metadata 329 330 @typing.final 331 def acquire(self) -> RESTClient: 332 """Acquires a new `RESTClient` instance from this REST pool. 333 334 Returns 335 ------- 336 `RESTClient` 337 An instance of a REST client. 338 """ 339 instance = RESTClient( 340 self._token, 341 client_secret=self._client_secret, 342 client_id=self._client_id, 343 max_retries=self._max_retries, 344 max_ratelimit_retries=self._max_rate_limit_retries, 345 enable_debugging=self._enable_debug, 346 ) 347 return instance
Pool of RESTClient instances.
This allows to create multiple instances of RESTClients that can be acquired
which share the same connector and metadata.
Example
import aiobungie
client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.
async with client_pool.acquire() as client:
await client.download_manifest()
return client.build_oauth2_url()
async with client_pool.acquire() as client:
new_tokens = await client.refresh_access_token("token")
# Tokens now can be used from any pool.
client.metadata['tokens'] = new_tokens
Parameters
- token (
str): A valid application token from Bungie's developer portal.
Other Parameters
- max_retries (
int): The max retries number to retry if the request hit a5xxstatus code. - max_ratelimit_retries (
int): The max retries number to retry if the request hit a429status code. Defaults to3. - client_secret (
typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. - client_id (
typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client. - enable_debugging (
bool | str): Whether to enable logging responses or not.
Logging Levels
False: This will disable logging.True: This will set the level toDEBUGand enable logging minimal information. Like the response status, route, taken time and so on."TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
302 def __init__( 303 self, 304 token: str, 305 /, 306 client_secret: typing.Optional[str] = None, 307 client_id: typing.Optional[int] = None, 308 *, 309 max_retries: int = 4, 310 max_rate_limit_retries: int = 3, 311 enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False, 312 ) -> None: 313 self._client_secret = client_secret 314 self._client_id = client_id 315 self._token: str = token 316 self._max_retries = max_retries 317 self._max_rate_limit_retries = max_rate_limit_retries 318 self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {} 319 self._enable_debug = enable_debugging
Pool's Metadata. This is different from client instance metadata.
330 @typing.final 331 def acquire(self) -> RESTClient: 332 """Acquires a new `RESTClient` instance from this REST pool. 333 334 Returns 335 ------- 336 `RESTClient` 337 An instance of a REST client. 338 """ 339 instance = RESTClient( 340 self._token, 341 client_secret=self._client_secret, 342 client_id=self._client_id, 343 max_retries=self._max_retries, 344 max_ratelimit_retries=self._max_rate_limit_retries, 345 enable_debugging=self._enable_debug, 346 ) 347 return instance
Acquires a new RESTClient instance from this REST pool.
Returns
RESTClient: An instance of a REST client.
496@typing.final 497class Race(int, Enum): 498 """An Enum for Destiny races.""" 499 500 HUMAN = 0 501 AWOKEN = 1 502 EXO = 2 503 UNKNOWN = 3
An Enum for Destiny races.
148@typing.final 149class Raid(int, Enum): 150 """An Enum for all available raids in Destiny 2.""" 151 152 DSC = 910380154 153 """Deep Stone Crypt""" 154 155 LW = 2122313384 156 """Last Wish""" 157 158 VOG = 3881495763 159 """Normal Valut of Glass""" 160 161 GOS = 3458480158 162 """Garden Of Salvation"""
An Enum for all available raids in Destiny 2.
213@attrs.define(auto_exc=True) 214class RateLimitedError(HTTPError): 215 """Raised when being hit with ratelimits.""" 216 217 http_status: http.HTTPStatus = attrs.field( 218 default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False 219 ) 220 """The request response http status.""" 221 222 url: typedefs.StrOrURL 223 """The URL/endpoint caused this error.""" 224 225 body: typing.Any 226 """The response body.""" 227 228 retry_after: float = attrs.field(default=0.0) 229 """The amount of seconds you need to wait before retrying to requests.""" 230 231 message: str = attrs.field(init=False) 232 """A Bungie human readable message describes the cause of the error.""" 233 234 @message.default # type: ignore 235 def _(self) -> str: 236 return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!" 237 238 def __str__(self) -> str: 239 return self.message
Raised when being hit with ratelimits.
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default): 3 self.http_status = attr_dict['http_status'].default 4 self.url = url 5 self.body = body 6 self.retry_after = retry_after 7 self.message = __attr_factory_message(self) 8 BaseException.__init__(self, self.url,self.body,self.retry_after)
Method generated by attrs for class RateLimitedError.
Inherited Members
- builtins.BaseException
- with_traceback
- args
49@typing.final 50class RecordState(enums.Flag): 51 """An enum for records component states.""" 52 53 NONE = 0 54 REDEEMED = 1 55 UNAVAILABLE = 2 56 OBJECTIVE_NOT_COMPLETED = 4 57 OBSCURED = 8 58 INVISIBLE = 16 59 ENTITLEMENT_UNOWNED = 32 60 CAN_EQUIP_TITLE = 64
An enum for records component states.
691@typing.final 692class Relationship(int, Enum): 693 """An enum for bungie friends relationship types.""" 694 695 UNKNOWN = 0 696 FRIEND = 1 697 INCOMING_REQUEST = 2 698 OUTGOING_REQUEST = 3
An enum for bungie friends relationship types.
215class RequestMethod(str, enums.Enum): 216 """HTTP request methods enum.""" 217 218 GET = "GET" 219 """GET methods.""" 220 POST = "POST" 221 """POST methods.""" 222 PUT = "PUT" 223 """PUT methods.""" 224 PATCH = "PATCH" 225 """PATCH methods.""" 226 DELETE = "DELETE" 227 """DELETE methods"""
HTTP request methods enum.
Inherited Members
- builtins.str
- encode
- replace
- split
- rsplit
- join
- capitalize
- casefold
- title
- center
- count
- expandtabs
- find
- partition
- index
- ljust
- lower
- lstrip
- rfind
- rindex
- rjust
- rstrip
- rpartition
- splitlines
- strip
- swapcase
- translate
- upper
- startswith
- endswith
- removeprefix
- removesuffix
- isascii
- islower
- isupper
- istitle
- isspace
- isdecimal
- isdigit
- isnumeric
- isalpha
- isalnum
- isidentifier
- isprintable
- zfill
- format
- format_map
- maketrans
208@attrs.define(auto_exc=True) 209class ResponseError(HTTPException): 210 """Standard HTTP responses exception."""
Standard HTTP responses exception.
2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data): 3 self.error_code = error_code 4 self.http_status = http_status 5 self.throttle_seconds = throttle_seconds 6 self.url = url 7 self.body = body 8 self.headers = headers 9 self.message = message 10 self.error_status = error_status 11 self.message_data = message_data 12 BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)
Method generated by attrs for class ResponseError.
Inherited Members
- HTTPException
- error_code
- http_status
- throttle_seconds
- url
- body
- headers
- message
- error_status
- message_data
- builtins.BaseException
- with_traceback
- args
518@typing.final 519class Stat(int, Enum): 520 """An Enum for Destiny 2 character stats.""" 521 522 NONE = 0 523 MOBILITY = 2996146975 524 RESILIENCE = 392767087 525 RECOVERY = 1943323491 526 DISCIPLINE = 1735777505 527 INTELLECT = 144602215 528 STRENGTH = 4244567218 529 LIGHT_POWER = 1935470627
An Enum for Destiny 2 character stats.
633@typing.final 634class TierType(int, Enum): 635 """An enum for a Destiny 2 item tier type.""" 636 637 UNKNOWN = 0 638 CURRENCY = 1 639 BASIC = 2 640 COMMON = 3 641 RARE = 4 642 SUPERIOR = 5 643 EXOTIC = 6
An enum for a Destiny 2 item tier type.
743@typing.final 744class TransferStatus(Flag): 745 """An enum for items transfer statuses.""" 746 747 CAN_TRANSFER = 0 748 """The item can be transferred.""" 749 IS_EQUIPPED = 1 750 """You can't transfer since the item is equipped.""" 751 NOT_TRASNFERRABLE = 2 752 """This item can not be transferred.""" 753 COULD_BE_TRANSFERRED = 4 754 """You can trasnfer the item. But the place you're trying to put it at has no space for it."""
An enum for items transfer statuses.
You can trasnfer the item. But the place you're trying to put it at has no space for it.
33class UndefinedType: 34 """An `UNDEFINED` type.""" 35 36 __instance: typing.Optional[UndefinedType] = None 37 38 def __bool__(self) -> typing.Literal[False]: 39 return False 40 41 def __int__(self) -> typing.Literal[0]: 42 return 0 43 44 def __repr__(self) -> str: 45 return "UNDEFINED" 46 47 def __str__(self) -> str: 48 return "UNDEFINED" 49 50 def __new__(cls) -> UndefinedType: 51 if cls.__instance is None: 52 o = super().__new__(cls) 53 cls.__instance = o 54 return cls.__instance
An UNDEFINED type.
75@typing.final 76class ValueUIStyle(int, enums.Enum): 77 AUTOMATIC = 0 78 FRACTION = 1 79 CHECK_BOX = 2 80 PERCENTAGE = 3 81 DATETIME = 4 82 FRACTION_FLOAT = 5 83 INTEGER = 6 84 TIME_DURATION = 7 85 HIDDEN = 8 86 MULTIPLIER = 9 87 GREEN_PIPS = 10 88 RED_PIPS = 11 89 EXPLICIT_PERCENTAGE = 12 90 RAW_FLOAT = 13 91 LEVEL_AND_REWARD = 14
An enumeration.
245@typing.final 246class Vendor(int, Enum): 247 """An Enum for all available vendors in Destiny 2.""" 248 249 ZAVALA = 69482069 250 XUR = 2190858386 251 BANSHE = 672118013 252 SPIDER = 863940356 253 SHAXX = 3603221665 254 KADI = 529635856 255 """Postmaster exo.""" 256 YUNA = 1796504621 257 """Asia servers only.""" 258 EVERVERSE = 3361454721 259 AMANDA = 460529231 260 """Amanda holiday""" 261 CROW = 3611983588 262 HAWTHORNE = 3347378076 263 ADA1 = 350061650 264 DRIFTER = 248695599 265 IKORA = 1976548992 266 SAINT = 765357505 267 """Saint-14""" 268 ERIS_MORN = 1616085565 269 SHAW_HAWN = 1816541247 270 """COSMODROME Guy""" 271 VARIKS = 2531198101
An Enum for all available vendors in Destiny 2.
532@typing.final 533class WeaponType(int, Enum): 534 """Enums for The three Destiny Weapon Types""" 535 536 NONE = 0 537 KINETIC = 1498876634 538 ENERGY = 2465295065 539 POWER = 953998645
Enums for The three Destiny Weapon Types
594def into_iter( 595 iterable: collections.Iterable[Item], 596) -> FlatIterator[Item]: 597 """Converts an iterable into an flat iterator. 598 599 Example 600 ------- 601 >>> sequence = [1,2,3] 602 >>> async for item in aiobungie.into_iter(sequence).reversed(): 603 print(item) 604 # 3 605 # 2 606 # 1 607 608 Parameters 609 ---------- 610 iterable: `typing.Iterable[Item]` 611 The iterable to convert. 612 613 Raises 614 ------ 615 `StopIteration` 616 If no elements are left in the iterator. 617 """ 618 return FlatIterator(iterable)
Converts an iterable into an flat iterator.
Example
>>> sequence = [1,2,3]
>>> async for item in aiobungie.into_iter(sequence).reversed():
print(item)
<h1 id="3">3</h1>
2
1
Parameters
- iterable (
typing.Iterable[Item]): The iterable to convert.
Raises
StopIteration: If no elements are left in the iterator.
242async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError: 243 """Generates and raise exceptions on error responses.""" 244 245 # Not a JSON response, raise immediately. 246 247 # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized 248 # request with a dummy access token. I can't really do anything about this.. 249 if response.content_type != "application/json": 250 return HTTPError( 251 f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}", 252 http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE, 253 ) 254 255 body = await response.json() 256 message: str = body.get("Message", "UNDEFINED_MESSAGE") 257 error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS") 258 message_data: dict[str, str] = body.get("MessageData", {}) 259 throttle_seconds: int = body.get("ThrottleSeconds", 0) 260 error_code: int = body.get("ErrorCode", 0) 261 262 # Standard HTTP status. 263 if response.status == http.HTTPStatus.NOT_FOUND: 264 return NotFound( 265 message=message, 266 error_code=error_code, 267 throttle_seconds=throttle_seconds, 268 url=str(response.real_url), 269 body=body, 270 headers=response.headers, 271 error_status=error_status, 272 message_data=message_data, 273 ) 274 275 elif response.status == http.HTTPStatus.FORBIDDEN: 276 return Forbidden( 277 message=message, 278 error_code=error_code, 279 throttle_seconds=throttle_seconds, 280 url=str(response.real_url), 281 body=body, 282 headers=response.headers, 283 error_status=error_status, 284 message_data=message_data, 285 ) 286 287 elif response.status == http.HTTPStatus.UNAUTHORIZED: 288 return Unauthorized( 289 message=message, 290 error_code=error_code, 291 throttle_seconds=throttle_seconds, 292 url=str(response.real_url), 293 body=body, 294 headers=response.headers, 295 error_status=error_status, 296 message_data=message_data, 297 ) 298 299 elif response.status == http.HTTPStatus.BAD_REQUEST: 300 # Membership needs to be alone. 301 if error_status == "InvalidParameters": 302 return MembershipTypeError( 303 message=message, 304 body=body, 305 headers=response.headers, 306 url=str(response.url), 307 membership_type=message_data["membershipType"], 308 required_membership=message_data["membershipInfo.membershipType"], 309 membership_id=int(message_data["membershipId"]), 310 ) 311 return BadRequest( 312 message=message, 313 body=body, 314 headers=response.headers, 315 url=str(response.url), 316 ) 317 318 status = http.HTTPStatus(response.status) 319 320 if 400 <= status < 500: 321 return ResponseError( 322 message=message, 323 error_code=error_code, 324 throttle_seconds=throttle_seconds, 325 url=str(response.real_url), 326 body=body, 327 headers=response.headers, 328 error_status=error_status, 329 message_data=message_data, 330 http_status=status, 331 ) 332 333 # Need to self handle ~5xx errors 334 elif 500 <= status < 600: 335 # No API key or method requires OAuth2 most likely. 336 if error_status in { 337 "ApiKeyMissingFromRequest", 338 "WebAuthRequired", 339 "ApiInvalidOrExpiredKey", 340 "AuthenticationInvalid", 341 "AuthorizationCodeInvalid", 342 }: 343 return Unauthorized( 344 message=message, 345 error_code=error_code, 346 throttle_seconds=throttle_seconds, 347 url=str(response.real_url), 348 body=body, 349 headers=response.headers, 350 error_status=error_status, 351 message_data=message_data, 352 ) 353 354 # Anything contains not found. 355 elif ( 356 "NotFound" in error_status or error_status == "UserCannotFindRequestedUser" 357 ): 358 return NotFound( 359 message=message, 360 error_code=error_code, 361 throttle_seconds=throttle_seconds, 362 url=str(response.real_url), 363 body=body, 364 headers=response.headers, 365 error_status=error_status, 366 message_data=message_data, 367 ) 368 369 # Other 5xx errors. 370 else: 371 return InternalServerError( 372 message=message, 373 error_code=error_code, 374 throttle_seconds=throttle_seconds, 375 url=str(response.real_url), 376 body=body, 377 headers=response.headers, 378 error_status=error_status, 379 message_data=message_data, 380 http_status=status, 381 ) 382 # Something else. 383 else: 384 return HTTPException( 385 message=message, 386 error_code=error_code, 387 throttle_seconds=throttle_seconds, 388 url=str(response.real_url), 389 body=body, 390 headers=response.headers, 391 error_status=error_status, 392 message_data=message_data, 393 http_status=status, 394 )
Generates and raise exceptions on error responses.
397def stringify_http_message(headers: collections.Mapping[str, str]) -> str: 398 return ( 399 "{ \n" 400 + "\n".join( # noqa: W503 401 f"{f' {key}'}: {value}" 402 if key not in ("Authorization", "X-API-KEY") 403 else f" {key}: HIDDEN_TOKEN" 404 for key, value in headers.items() 405 ) 406 + "\n}" # noqa: W503 407 )